binding_test.go 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144
  1. // Copyright 2014 Manu Martinez-Almeida. All rights reserved.
  2. // Use of this source code is governed by a MIT style
  3. // license that can be found in the LICENSE file.
  4. package binding
  5. import (
  6. "bytes"
  7. "encoding/json"
  8. "errors"
  9. "io"
  10. "io/ioutil"
  11. "mime/multipart"
  12. "net/http"
  13. "os"
  14. "strconv"
  15. "strings"
  16. "testing"
  17. "time"
  18. "github.com/gin-gonic/gin/testdata/protoexample"
  19. "github.com/golang/protobuf/proto"
  20. "github.com/stretchr/testify/assert"
  21. "github.com/ugorji/go/codec"
  22. )
  23. type FooStruct struct {
  24. Foo string `msgpack:"foo" json:"foo" form:"foo" xml:"foo" binding:"required"`
  25. }
  26. type FooBarStruct struct {
  27. FooStruct
  28. Bar string `msgpack:"bar" json:"bar" form:"bar" xml:"bar" binding:"required"`
  29. }
  30. type FooBarFileStruct struct {
  31. FooBarStruct
  32. File *multipart.FileHeader `form:"file" binding:"required"`
  33. }
  34. type FooBarFileFailStruct struct {
  35. FooBarStruct
  36. File *multipart.FileHeader `invalid_name:"file" binding:"required"`
  37. // for unexport test
  38. data *multipart.FileHeader `form:"data" binding:"required"`
  39. }
  40. type FooDefaultBarStruct struct {
  41. FooStruct
  42. Bar string `msgpack:"bar" json:"bar" form:"bar,default=hello" xml:"bar" binding:"required"`
  43. }
  44. type FooStructUseNumber struct {
  45. Foo interface{} `json:"foo" binding:"required"`
  46. }
  47. type FooBarStructForTimeType struct {
  48. TimeFoo time.Time `form:"time_foo" time_format:"2006-01-02" time_utc:"1" time_location:"Asia/Chongqing"`
  49. TimeBar time.Time `form:"time_bar" time_format:"2006-01-02" time_utc:"1"`
  50. }
  51. type FooStructForTimeTypeNotFormat struct {
  52. TimeFoo time.Time `form:"time_foo"`
  53. }
  54. type FooStructForTimeTypeFailFormat struct {
  55. TimeFoo time.Time `form:"time_foo" time_format:"2017-11-15"`
  56. }
  57. type FooStructForTimeTypeFailLocation struct {
  58. TimeFoo time.Time `form:"time_foo" time_format:"2006-01-02" time_location:"/asia/chongqing"`
  59. }
  60. type FooStructForMapType struct {
  61. MapFoo map[string]interface{} `form:"map_foo"`
  62. }
  63. type FooStructForIgnoreFormTag struct {
  64. Foo *string `form:"-"`
  65. }
  66. type InvalidNameType struct {
  67. TestName string `invalid_name:"test_name"`
  68. }
  69. type InvalidNameMapType struct {
  70. TestName struct {
  71. MapFoo map[string]interface{} `form:"map_foo"`
  72. }
  73. }
  74. type FooStructForSliceType struct {
  75. SliceFoo []int `form:"slice_foo"`
  76. }
  77. type FooStructForStructType struct {
  78. StructFoo struct {
  79. Idx int `form:"idx"`
  80. }
  81. }
  82. type FooStructForStructPointerType struct {
  83. StructPointerFoo *struct {
  84. Name string `form:"name"`
  85. }
  86. }
  87. type FooStructForSliceMapType struct {
  88. // Unknown type: not support map
  89. SliceMapFoo []map[string]interface{} `form:"slice_map_foo"`
  90. }
  91. type FooStructForBoolType struct {
  92. BoolFoo bool `form:"bool_foo"`
  93. }
  94. type FooStructForStringPtrType struct {
  95. PtrFoo *string `form:"ptr_foo"`
  96. PtrBar *string `form:"ptr_bar" binding:"required"`
  97. }
  98. type FooStructForMapPtrType struct {
  99. PtrBar *map[string]interface{} `form:"ptr_bar"`
  100. }
  101. func TestBindingDefault(t *testing.T) {
  102. assert.Equal(t, Form, Default("GET", ""))
  103. assert.Equal(t, Form, Default("GET", MIMEJSON))
  104. assert.Equal(t, JSON, Default("POST", MIMEJSON))
  105. assert.Equal(t, JSON, Default("PUT", MIMEJSON))
  106. assert.Equal(t, XML, Default("POST", MIMEXML))
  107. assert.Equal(t, XML, Default("PUT", MIMEXML2))
  108. assert.Equal(t, Form, Default("POST", MIMEPOSTForm))
  109. assert.Equal(t, Form, Default("PUT", MIMEPOSTForm))
  110. assert.Equal(t, FormMultipart, Default("POST", MIMEMultipartPOSTForm))
  111. assert.Equal(t, FormMultipart, Default("PUT", MIMEMultipartPOSTForm))
  112. assert.Equal(t, ProtoBuf, Default("POST", MIMEPROTOBUF))
  113. assert.Equal(t, ProtoBuf, Default("PUT", MIMEPROTOBUF))
  114. assert.Equal(t, MsgPack, Default("POST", MIMEMSGPACK))
  115. assert.Equal(t, MsgPack, Default("PUT", MIMEMSGPACK2))
  116. assert.Equal(t, YAML, Default("POST", MIMEYAML))
  117. assert.Equal(t, YAML, Default("PUT", MIMEYAML))
  118. }
  119. func TestBindingJSONNilBody(t *testing.T) {
  120. var obj FooStruct
  121. req, _ := http.NewRequest(http.MethodPost, "/", nil)
  122. err := JSON.Bind(req, &obj)
  123. assert.Error(t, err)
  124. }
  125. func TestBindingJSON(t *testing.T) {
  126. testBodyBinding(t,
  127. JSON, "json",
  128. "/", "/",
  129. `{"foo": "bar"}`, `{"bar": "foo"}`)
  130. }
  131. func TestBindingJSONUseNumber(t *testing.T) {
  132. testBodyBindingUseNumber(t,
  133. JSON, "json",
  134. "/", "/",
  135. `{"foo": 123}`, `{"bar": "foo"}`)
  136. }
  137. func TestBindingJSONUseNumber2(t *testing.T) {
  138. testBodyBindingUseNumber2(t,
  139. JSON, "json",
  140. "/", "/",
  141. `{"foo": 123}`, `{"bar": "foo"}`)
  142. }
  143. func TestBindingForm(t *testing.T) {
  144. testFormBinding(t, "POST",
  145. "/", "/",
  146. "foo=bar&bar=foo", "bar2=foo")
  147. }
  148. func TestBindingForm2(t *testing.T) {
  149. testFormBinding(t, "GET",
  150. "/?foo=bar&bar=foo", "/?bar2=foo",
  151. "", "")
  152. }
  153. func TestBindingFormDefaultValue(t *testing.T) {
  154. testFormBindingDefaultValue(t, "POST",
  155. "/", "/",
  156. "foo=bar", "bar2=foo")
  157. }
  158. func TestBindingFormDefaultValue2(t *testing.T) {
  159. testFormBindingDefaultValue(t, "GET",
  160. "/?foo=bar", "/?bar2=foo",
  161. "", "")
  162. }
  163. func TestBindingFormForTime(t *testing.T) {
  164. testFormBindingForTime(t, "POST",
  165. "/", "/",
  166. "time_foo=2017-11-15&time_bar=", "bar2=foo")
  167. testFormBindingForTimeNotFormat(t, "POST",
  168. "/", "/",
  169. "time_foo=2017-11-15", "bar2=foo")
  170. testFormBindingForTimeFailFormat(t, "POST",
  171. "/", "/",
  172. "time_foo=2017-11-15", "bar2=foo")
  173. testFormBindingForTimeFailLocation(t, "POST",
  174. "/", "/",
  175. "time_foo=2017-11-15", "bar2=foo")
  176. }
  177. func TestBindingFormForTime2(t *testing.T) {
  178. testFormBindingForTime(t, "GET",
  179. "/?time_foo=2017-11-15&time_bar=", "/?bar2=foo",
  180. "", "")
  181. testFormBindingForTimeNotFormat(t, "GET",
  182. "/?time_foo=2017-11-15", "/?bar2=foo",
  183. "", "")
  184. testFormBindingForTimeFailFormat(t, "GET",
  185. "/?time_foo=2017-11-15", "/?bar2=foo",
  186. "", "")
  187. testFormBindingForTimeFailLocation(t, "GET",
  188. "/?time_foo=2017-11-15", "/?bar2=foo",
  189. "", "")
  190. }
  191. func TestFormBindingIgnoreField(t *testing.T) {
  192. testFormBindingIgnoreField(t, "POST",
  193. "/", "/",
  194. "-=bar", "")
  195. }
  196. func TestBindingFormInvalidName(t *testing.T) {
  197. testFormBindingInvalidName(t, "POST",
  198. "/", "/",
  199. "test_name=bar", "bar2=foo")
  200. }
  201. func TestBindingFormInvalidName2(t *testing.T) {
  202. testFormBindingInvalidName2(t, "POST",
  203. "/", "/",
  204. "map_foo=bar", "bar2=foo")
  205. }
  206. func TestBindingFormForType(t *testing.T) {
  207. testFormBindingForType(t, "POST",
  208. "/", "/",
  209. "map_foo={\"bar\":123}", "map_foo=1", "Map")
  210. testFormBindingForType(t, "POST",
  211. "/", "/",
  212. "slice_foo=1&slice_foo=2", "bar2=1&bar2=2", "Slice")
  213. testFormBindingForType(t, "GET",
  214. "/?slice_foo=1&slice_foo=2", "/?bar2=1&bar2=2",
  215. "", "", "Slice")
  216. testFormBindingForType(t, "POST",
  217. "/", "/",
  218. "slice_map_foo=1&slice_map_foo=2", "bar2=1&bar2=2", "SliceMap")
  219. testFormBindingForType(t, "GET",
  220. "/?slice_map_foo=1&slice_map_foo=2", "/?bar2=1&bar2=2",
  221. "", "", "SliceMap")
  222. testFormBindingForType(t, "POST",
  223. "/", "/",
  224. "ptr_bar=test", "bar2=test", "Ptr")
  225. testFormBindingForType(t, "GET",
  226. "/?ptr_bar=test", "/?bar2=test",
  227. "", "", "Ptr")
  228. testFormBindingForType(t, "POST",
  229. "/", "/",
  230. "idx=123", "id1=1", "Struct")
  231. testFormBindingForType(t, "GET",
  232. "/?idx=123", "/?id1=1",
  233. "", "", "Struct")
  234. testFormBindingForType(t, "POST",
  235. "/", "/",
  236. "name=thinkerou", "name1=ou", "StructPointer")
  237. testFormBindingForType(t, "GET",
  238. "/?name=thinkerou", "/?name1=ou",
  239. "", "", "StructPointer")
  240. }
  241. func TestBindingQuery(t *testing.T) {
  242. testQueryBinding(t, "POST",
  243. "/?foo=bar&bar=foo", "/",
  244. "foo=unused", "bar2=foo")
  245. }
  246. func TestBindingQuery2(t *testing.T) {
  247. testQueryBinding(t, "GET",
  248. "/?foo=bar&bar=foo", "/?bar2=foo",
  249. "foo=unused", "")
  250. }
  251. func TestBindingQueryFail(t *testing.T) {
  252. testQueryBindingFail(t, "POST",
  253. "/?map_foo=", "/",
  254. "map_foo=unused", "bar2=foo")
  255. }
  256. func TestBindingQueryFail2(t *testing.T) {
  257. testQueryBindingFail(t, "GET",
  258. "/?map_foo=", "/?bar2=foo",
  259. "map_foo=unused", "")
  260. }
  261. func TestBindingQueryBoolFail(t *testing.T) {
  262. testQueryBindingBoolFail(t, "GET",
  263. "/?bool_foo=fasl", "/?bar2=foo",
  264. "bool_foo=unused", "")
  265. }
  266. func TestBindingXML(t *testing.T) {
  267. testBodyBinding(t,
  268. XML, "xml",
  269. "/", "/",
  270. "<map><foo>bar</foo></map>", "<map><bar>foo</bar></map>")
  271. }
  272. func TestBindingXMLFail(t *testing.T) {
  273. testBodyBindingFail(t,
  274. XML, "xml",
  275. "/", "/",
  276. "<map><foo>bar<foo></map>", "<map><bar>foo</bar></map>")
  277. }
  278. func TestBindingYAML(t *testing.T) {
  279. testBodyBinding(t,
  280. YAML, "yaml",
  281. "/", "/",
  282. `foo: bar`, `bar: foo`)
  283. }
  284. func TestBindingYAMLFail(t *testing.T) {
  285. testBodyBindingFail(t,
  286. YAML, "yaml",
  287. "/", "/",
  288. `foo:\nbar`, `bar: foo`)
  289. }
  290. func createFormPostRequest(t *testing.T) *http.Request {
  291. req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar&bar=foo"))
  292. assert.NoError(t, err)
  293. req.Header.Set("Content-Type", MIMEPOSTForm)
  294. return req
  295. }
  296. func createDefaultFormPostRequest(t *testing.T) *http.Request {
  297. req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar"))
  298. assert.NoError(t, err)
  299. req.Header.Set("Content-Type", MIMEPOSTForm)
  300. return req
  301. }
  302. func createFormPostRequestForMap(t *testing.T) *http.Request {
  303. req, err := http.NewRequest("POST", "/?map_foo=getfoo", bytes.NewBufferString("map_foo={\"bar\":123}"))
  304. assert.NoError(t, err)
  305. req.Header.Set("Content-Type", MIMEPOSTForm)
  306. return req
  307. }
  308. func createFormPostRequestForMapFail(t *testing.T) *http.Request {
  309. req, err := http.NewRequest("POST", "/?map_foo=getfoo", bytes.NewBufferString("map_foo=hello"))
  310. assert.NoError(t, err)
  311. req.Header.Set("Content-Type", MIMEPOSTForm)
  312. return req
  313. }
  314. func createFormFilesMultipartRequest(t *testing.T) *http.Request {
  315. boundary := "--testboundary"
  316. body := new(bytes.Buffer)
  317. mw := multipart.NewWriter(body)
  318. defer mw.Close()
  319. assert.NoError(t, mw.SetBoundary(boundary))
  320. assert.NoError(t, mw.WriteField("foo", "bar"))
  321. assert.NoError(t, mw.WriteField("bar", "foo"))
  322. f, err := os.Open("form.go")
  323. assert.NoError(t, err)
  324. defer f.Close()
  325. fw, err1 := mw.CreateFormFile("file", "form.go")
  326. assert.NoError(t, err1)
  327. io.Copy(fw, f)
  328. req, err2 := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
  329. assert.NoError(t, err2)
  330. req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
  331. return req
  332. }
  333. func createFormFilesMultipartRequestFail(t *testing.T) *http.Request {
  334. boundary := "--testboundary"
  335. body := new(bytes.Buffer)
  336. mw := multipart.NewWriter(body)
  337. defer mw.Close()
  338. assert.NoError(t, mw.SetBoundary(boundary))
  339. assert.NoError(t, mw.WriteField("foo", "bar"))
  340. assert.NoError(t, mw.WriteField("bar", "foo"))
  341. f, err := os.Open("form.go")
  342. assert.NoError(t, err)
  343. defer f.Close()
  344. fw, err1 := mw.CreateFormFile("file_foo", "form_foo.go")
  345. assert.NoError(t, err1)
  346. io.Copy(fw, f)
  347. req, err2 := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
  348. assert.NoError(t, err2)
  349. req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
  350. return req
  351. }
  352. func createFormMultipartRequest(t *testing.T) *http.Request {
  353. boundary := "--testboundary"
  354. body := new(bytes.Buffer)
  355. mw := multipart.NewWriter(body)
  356. defer mw.Close()
  357. assert.NoError(t, mw.SetBoundary(boundary))
  358. assert.NoError(t, mw.WriteField("foo", "bar"))
  359. assert.NoError(t, mw.WriteField("bar", "foo"))
  360. req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
  361. assert.NoError(t, err)
  362. req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
  363. return req
  364. }
  365. func createFormMultipartRequestForMap(t *testing.T) *http.Request {
  366. boundary := "--testboundary"
  367. body := new(bytes.Buffer)
  368. mw := multipart.NewWriter(body)
  369. defer mw.Close()
  370. assert.NoError(t, mw.SetBoundary(boundary))
  371. assert.NoError(t, mw.WriteField("map_foo", "{\"bar\":123, \"name\":\"thinkerou\", \"pai\": 3.14}"))
  372. req, err := http.NewRequest("POST", "/?map_foo=getfoo", body)
  373. assert.NoError(t, err)
  374. req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
  375. return req
  376. }
  377. func createFormMultipartRequestForMapFail(t *testing.T) *http.Request {
  378. boundary := "--testboundary"
  379. body := new(bytes.Buffer)
  380. mw := multipart.NewWriter(body)
  381. defer mw.Close()
  382. assert.NoError(t, mw.SetBoundary(boundary))
  383. assert.NoError(t, mw.WriteField("map_foo", "3.14"))
  384. req, err := http.NewRequest("POST", "/?map_foo=getfoo", body)
  385. assert.NoError(t, err)
  386. req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
  387. return req
  388. }
  389. func TestBindingFormPost(t *testing.T) {
  390. req := createFormPostRequest(t)
  391. var obj FooBarStruct
  392. assert.NoError(t, FormPost.Bind(req, &obj))
  393. assert.Equal(t, "form-urlencoded", FormPost.Name())
  394. assert.Equal(t, "bar", obj.Foo)
  395. assert.Equal(t, "foo", obj.Bar)
  396. }
  397. func TestBindingDefaultValueFormPost(t *testing.T) {
  398. req := createDefaultFormPostRequest(t)
  399. var obj FooDefaultBarStruct
  400. assert.NoError(t, FormPost.Bind(req, &obj))
  401. assert.Equal(t, "bar", obj.Foo)
  402. assert.Equal(t, "hello", obj.Bar)
  403. }
  404. func TestBindingFormPostForMap(t *testing.T) {
  405. req := createFormPostRequestForMap(t)
  406. var obj FooStructForMapType
  407. err := FormPost.Bind(req, &obj)
  408. assert.NoError(t, err)
  409. assert.Equal(t, float64(123), obj.MapFoo["bar"].(float64))
  410. }
  411. func TestBindingFormPostForMapFail(t *testing.T) {
  412. req := createFormPostRequestForMapFail(t)
  413. var obj FooStructForMapType
  414. err := FormPost.Bind(req, &obj)
  415. assert.Error(t, err)
  416. }
  417. func TestBindingFormFilesMultipart(t *testing.T) {
  418. req := createFormFilesMultipartRequest(t)
  419. var obj FooBarFileStruct
  420. FormMultipart.Bind(req, &obj)
  421. // file from os
  422. f, _ := os.Open("form.go")
  423. defer f.Close()
  424. fileActual, _ := ioutil.ReadAll(f)
  425. // file from multipart
  426. mf, _ := obj.File.Open()
  427. defer mf.Close()
  428. fileExpect, _ := ioutil.ReadAll(mf)
  429. assert.Equal(t, FormMultipart.Name(), "multipart/form-data")
  430. assert.Equal(t, obj.Foo, "bar")
  431. assert.Equal(t, obj.Bar, "foo")
  432. assert.Equal(t, fileExpect, fileActual)
  433. }
  434. func TestBindingFormFilesMultipartFail(t *testing.T) {
  435. req := createFormFilesMultipartRequestFail(t)
  436. var obj FooBarFileFailStruct
  437. err := FormMultipart.Bind(req, &obj)
  438. assert.Error(t, err)
  439. }
  440. func TestBindingFormMultipart(t *testing.T) {
  441. req := createFormMultipartRequest(t)
  442. var obj FooBarStruct
  443. assert.NoError(t, FormMultipart.Bind(req, &obj))
  444. assert.Equal(t, "multipart/form-data", FormMultipart.Name())
  445. assert.Equal(t, "bar", obj.Foo)
  446. assert.Equal(t, "foo", obj.Bar)
  447. }
  448. func TestBindingFormMultipartForMap(t *testing.T) {
  449. req := createFormMultipartRequestForMap(t)
  450. var obj FooStructForMapType
  451. err := FormMultipart.Bind(req, &obj)
  452. assert.NoError(t, err)
  453. assert.Equal(t, float64(123), obj.MapFoo["bar"].(float64))
  454. assert.Equal(t, "thinkerou", obj.MapFoo["name"].(string))
  455. assert.Equal(t, float64(3.14), obj.MapFoo["pai"].(float64))
  456. }
  457. func TestBindingFormMultipartForMapFail(t *testing.T) {
  458. req := createFormMultipartRequestForMapFail(t)
  459. var obj FooStructForMapType
  460. err := FormMultipart.Bind(req, &obj)
  461. assert.Error(t, err)
  462. }
  463. func TestBindingProtoBuf(t *testing.T) {
  464. test := &protoexample.Test{
  465. Label: proto.String("yes"),
  466. }
  467. data, _ := proto.Marshal(test)
  468. testProtoBodyBinding(t,
  469. ProtoBuf, "protobuf",
  470. "/", "/",
  471. string(data), string(data[1:]))
  472. }
  473. func TestBindingProtoBufFail(t *testing.T) {
  474. test := &protoexample.Test{
  475. Label: proto.String("yes"),
  476. }
  477. data, _ := proto.Marshal(test)
  478. testProtoBodyBindingFail(t,
  479. ProtoBuf, "protobuf",
  480. "/", "/",
  481. string(data), string(data[1:]))
  482. }
  483. func TestBindingMsgPack(t *testing.T) {
  484. test := FooStruct{
  485. Foo: "bar",
  486. }
  487. h := new(codec.MsgpackHandle)
  488. assert.NotNil(t, h)
  489. buf := bytes.NewBuffer([]byte{})
  490. assert.NotNil(t, buf)
  491. err := codec.NewEncoder(buf, h).Encode(test)
  492. assert.NoError(t, err)
  493. data := buf.Bytes()
  494. testMsgPackBodyBinding(t,
  495. MsgPack, "msgpack",
  496. "/", "/",
  497. string(data), string(data[1:]))
  498. }
  499. func TestValidationFails(t *testing.T) {
  500. var obj FooStruct
  501. req := requestWithBody("POST", "/", `{"bar": "foo"}`)
  502. err := JSON.Bind(req, &obj)
  503. assert.Error(t, err)
  504. }
  505. func TestValidationDisabled(t *testing.T) {
  506. backup := Validator
  507. Validator = nil
  508. defer func() { Validator = backup }()
  509. var obj FooStruct
  510. req := requestWithBody("POST", "/", `{"bar": "foo"}`)
  511. err := JSON.Bind(req, &obj)
  512. assert.NoError(t, err)
  513. }
  514. func TestExistsSucceeds(t *testing.T) {
  515. type HogeStruct struct {
  516. Hoge *int `json:"hoge" binding:"exists"`
  517. }
  518. var obj HogeStruct
  519. req := requestWithBody("POST", "/", `{"hoge": 0}`)
  520. err := JSON.Bind(req, &obj)
  521. assert.NoError(t, err)
  522. }
  523. func TestExistsFails(t *testing.T) {
  524. type HogeStruct struct {
  525. Hoge *int `json:"foo" binding:"exists"`
  526. }
  527. var obj HogeStruct
  528. req := requestWithBody("POST", "/", `{"boen": 0}`)
  529. err := JSON.Bind(req, &obj)
  530. assert.Error(t, err)
  531. }
  532. func TestUriBinding(t *testing.T) {
  533. b := Uri
  534. assert.Equal(t, "uri", b.Name())
  535. type Tag struct {
  536. Name string `uri:"name"`
  537. }
  538. var tag Tag
  539. m := make(map[string][]string)
  540. m["name"] = []string{"thinkerou"}
  541. assert.NoError(t, b.BindUri(m, &tag))
  542. assert.Equal(t, "thinkerou", tag.Name)
  543. type NotSupportStruct struct {
  544. Name map[string]interface{} `uri:"name"`
  545. }
  546. var not NotSupportStruct
  547. assert.Error(t, b.BindUri(m, &not))
  548. assert.Equal(t, map[string]interface{}(nil), not.Name)
  549. }
  550. func TestUriInnerBinding(t *testing.T) {
  551. type Tag struct {
  552. Name string `uri:"name"`
  553. S struct {
  554. Age int `uri:"age"`
  555. }
  556. }
  557. expectedName := "mike"
  558. expectedAge := 25
  559. m := map[string][]string{
  560. "name": {expectedName},
  561. "age": {strconv.Itoa(expectedAge)},
  562. }
  563. var tag Tag
  564. assert.NoError(t, Uri.BindUri(m, &tag))
  565. assert.Equal(t, tag.Name, expectedName)
  566. assert.Equal(t, tag.S.Age, expectedAge)
  567. }
  568. func testFormBinding(t *testing.T, method, path, badPath, body, badBody string) {
  569. b := Form
  570. assert.Equal(t, "form", b.Name())
  571. obj := FooBarStruct{}
  572. req := requestWithBody(method, path, body)
  573. if method == "POST" {
  574. req.Header.Add("Content-Type", MIMEPOSTForm)
  575. }
  576. err := b.Bind(req, &obj)
  577. assert.NoError(t, err)
  578. assert.Equal(t, "bar", obj.Foo)
  579. assert.Equal(t, "foo", obj.Bar)
  580. obj = FooBarStruct{}
  581. req = requestWithBody(method, badPath, badBody)
  582. err = JSON.Bind(req, &obj)
  583. assert.Error(t, err)
  584. }
  585. func testFormBindingDefaultValue(t *testing.T, method, path, badPath, body, badBody string) {
  586. b := Form
  587. assert.Equal(t, "form", b.Name())
  588. obj := FooDefaultBarStruct{}
  589. req := requestWithBody(method, path, body)
  590. if method == "POST" {
  591. req.Header.Add("Content-Type", MIMEPOSTForm)
  592. }
  593. err := b.Bind(req, &obj)
  594. assert.NoError(t, err)
  595. assert.Equal(t, "bar", obj.Foo)
  596. assert.Equal(t, "hello", obj.Bar)
  597. obj = FooDefaultBarStruct{}
  598. req = requestWithBody(method, badPath, badBody)
  599. err = JSON.Bind(req, &obj)
  600. assert.Error(t, err)
  601. }
  602. func TestFormBindingFail(t *testing.T) {
  603. b := Form
  604. assert.Equal(t, "form", b.Name())
  605. obj := FooBarStruct{}
  606. req, _ := http.NewRequest("POST", "/", nil)
  607. err := b.Bind(req, &obj)
  608. assert.Error(t, err)
  609. }
  610. func TestFormBindingMultipartFail(t *testing.T) {
  611. obj := FooBarStruct{}
  612. req, err := http.NewRequest("POST", "/", strings.NewReader("foo=bar"))
  613. assert.NoError(t, err)
  614. req.Header.Set("Content-Type", MIMEMultipartPOSTForm+";boundary=testboundary")
  615. _, err = req.MultipartReader()
  616. assert.NoError(t, err)
  617. err = Form.Bind(req, &obj)
  618. assert.Error(t, err)
  619. }
  620. func TestFormPostBindingFail(t *testing.T) {
  621. b := FormPost
  622. assert.Equal(t, "form-urlencoded", b.Name())
  623. obj := FooBarStruct{}
  624. req, _ := http.NewRequest("POST", "/", nil)
  625. err := b.Bind(req, &obj)
  626. assert.Error(t, err)
  627. }
  628. func TestFormMultipartBindingFail(t *testing.T) {
  629. b := FormMultipart
  630. assert.Equal(t, "multipart/form-data", b.Name())
  631. obj := FooBarStruct{}
  632. req, _ := http.NewRequest("POST", "/", nil)
  633. err := b.Bind(req, &obj)
  634. assert.Error(t, err)
  635. }
  636. func testFormBindingForTime(t *testing.T, method, path, badPath, body, badBody string) {
  637. b := Form
  638. assert.Equal(t, "form", b.Name())
  639. obj := FooBarStructForTimeType{}
  640. req := requestWithBody(method, path, body)
  641. if method == "POST" {
  642. req.Header.Add("Content-Type", MIMEPOSTForm)
  643. }
  644. err := b.Bind(req, &obj)
  645. assert.NoError(t, err)
  646. assert.Equal(t, int64(1510675200), obj.TimeFoo.Unix())
  647. assert.Equal(t, "Asia/Chongqing", obj.TimeFoo.Location().String())
  648. assert.Equal(t, int64(-62135596800), obj.TimeBar.Unix())
  649. assert.Equal(t, "UTC", obj.TimeBar.Location().String())
  650. obj = FooBarStructForTimeType{}
  651. req = requestWithBody(method, badPath, badBody)
  652. err = JSON.Bind(req, &obj)
  653. assert.Error(t, err)
  654. }
  655. func testFormBindingForTimeNotFormat(t *testing.T, method, path, badPath, body, badBody string) {
  656. b := Form
  657. assert.Equal(t, "form", b.Name())
  658. obj := FooStructForTimeTypeNotFormat{}
  659. req := requestWithBody(method, path, body)
  660. if method == "POST" {
  661. req.Header.Add("Content-Type", MIMEPOSTForm)
  662. }
  663. err := b.Bind(req, &obj)
  664. assert.Error(t, err)
  665. obj = FooStructForTimeTypeNotFormat{}
  666. req = requestWithBody(method, badPath, badBody)
  667. err = JSON.Bind(req, &obj)
  668. assert.Error(t, err)
  669. }
  670. func testFormBindingForTimeFailFormat(t *testing.T, method, path, badPath, body, badBody string) {
  671. b := Form
  672. assert.Equal(t, "form", b.Name())
  673. obj := FooStructForTimeTypeFailFormat{}
  674. req := requestWithBody(method, path, body)
  675. if method == "POST" {
  676. req.Header.Add("Content-Type", MIMEPOSTForm)
  677. }
  678. err := b.Bind(req, &obj)
  679. assert.Error(t, err)
  680. obj = FooStructForTimeTypeFailFormat{}
  681. req = requestWithBody(method, badPath, badBody)
  682. err = JSON.Bind(req, &obj)
  683. assert.Error(t, err)
  684. }
  685. func testFormBindingForTimeFailLocation(t *testing.T, method, path, badPath, body, badBody string) {
  686. b := Form
  687. assert.Equal(t, "form", b.Name())
  688. obj := FooStructForTimeTypeFailLocation{}
  689. req := requestWithBody(method, path, body)
  690. if method == "POST" {
  691. req.Header.Add("Content-Type", MIMEPOSTForm)
  692. }
  693. err := b.Bind(req, &obj)
  694. assert.Error(t, err)
  695. obj = FooStructForTimeTypeFailLocation{}
  696. req = requestWithBody(method, badPath, badBody)
  697. err = JSON.Bind(req, &obj)
  698. assert.Error(t, err)
  699. }
  700. func testFormBindingIgnoreField(t *testing.T, method, path, badPath, body, badBody string) {
  701. b := Form
  702. assert.Equal(t, "form", b.Name())
  703. obj := FooStructForIgnoreFormTag{}
  704. req := requestWithBody(method, path, body)
  705. if method == "POST" {
  706. req.Header.Add("Content-Type", MIMEPOSTForm)
  707. }
  708. err := b.Bind(req, &obj)
  709. assert.NoError(t, err)
  710. assert.Nil(t, obj.Foo)
  711. }
  712. func testFormBindingInvalidName(t *testing.T, method, path, badPath, body, badBody string) {
  713. b := Form
  714. assert.Equal(t, "form", b.Name())
  715. obj := InvalidNameType{}
  716. req := requestWithBody(method, path, body)
  717. if method == "POST" {
  718. req.Header.Add("Content-Type", MIMEPOSTForm)
  719. }
  720. err := b.Bind(req, &obj)
  721. assert.NoError(t, err)
  722. assert.Equal(t, "", obj.TestName)
  723. obj = InvalidNameType{}
  724. req = requestWithBody(method, badPath, badBody)
  725. err = JSON.Bind(req, &obj)
  726. assert.Error(t, err)
  727. }
  728. func testFormBindingInvalidName2(t *testing.T, method, path, badPath, body, badBody string) {
  729. b := Form
  730. assert.Equal(t, "form", b.Name())
  731. obj := InvalidNameMapType{}
  732. req := requestWithBody(method, path, body)
  733. if method == "POST" {
  734. req.Header.Add("Content-Type", MIMEPOSTForm)
  735. }
  736. err := b.Bind(req, &obj)
  737. assert.Error(t, err)
  738. obj = InvalidNameMapType{}
  739. req = requestWithBody(method, badPath, badBody)
  740. err = JSON.Bind(req, &obj)
  741. assert.Error(t, err)
  742. }
  743. func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody string, typ string) {
  744. b := Form
  745. assert.Equal(t, "form", b.Name())
  746. req := requestWithBody(method, path, body)
  747. if method == "POST" {
  748. req.Header.Add("Content-Type", MIMEPOSTForm)
  749. }
  750. switch typ {
  751. case "Slice":
  752. obj := FooStructForSliceType{}
  753. err := b.Bind(req, &obj)
  754. assert.NoError(t, err)
  755. assert.Equal(t, []int{1, 2}, obj.SliceFoo)
  756. obj = FooStructForSliceType{}
  757. req = requestWithBody(method, badPath, badBody)
  758. err = JSON.Bind(req, &obj)
  759. assert.Error(t, err)
  760. case "Struct":
  761. obj := FooStructForStructType{}
  762. err := b.Bind(req, &obj)
  763. assert.NoError(t, err)
  764. assert.Equal(t,
  765. struct {
  766. Idx int "form:\"idx\""
  767. }(struct {
  768. Idx int "form:\"idx\""
  769. }{Idx: 123}),
  770. obj.StructFoo)
  771. case "StructPointer":
  772. obj := FooStructForStructPointerType{}
  773. err := b.Bind(req, &obj)
  774. assert.NoError(t, err)
  775. assert.Equal(t,
  776. struct {
  777. Name string "form:\"name\""
  778. }(struct {
  779. Name string "form:\"name\""
  780. }{Name: "thinkerou"}),
  781. *obj.StructPointerFoo)
  782. case "Map":
  783. obj := FooStructForMapType{}
  784. err := b.Bind(req, &obj)
  785. assert.NoError(t, err)
  786. assert.Equal(t, float64(123), obj.MapFoo["bar"].(float64))
  787. case "SliceMap":
  788. obj := FooStructForSliceMapType{}
  789. err := b.Bind(req, &obj)
  790. assert.Error(t, err)
  791. case "Ptr":
  792. obj := FooStructForStringPtrType{}
  793. err := b.Bind(req, &obj)
  794. assert.NoError(t, err)
  795. assert.Nil(t, obj.PtrFoo)
  796. assert.Equal(t, "test", *obj.PtrBar)
  797. obj = FooStructForStringPtrType{}
  798. obj.PtrBar = new(string)
  799. err = b.Bind(req, &obj)
  800. assert.NoError(t, err)
  801. assert.Equal(t, "test", *obj.PtrBar)
  802. objErr := FooStructForMapPtrType{}
  803. err = b.Bind(req, &objErr)
  804. assert.Error(t, err)
  805. obj = FooStructForStringPtrType{}
  806. req = requestWithBody(method, badPath, badBody)
  807. err = b.Bind(req, &obj)
  808. assert.Error(t, err)
  809. }
  810. }
  811. func testQueryBinding(t *testing.T, method, path, badPath, body, badBody string) {
  812. b := Query
  813. assert.Equal(t, "query", b.Name())
  814. obj := FooBarStruct{}
  815. req := requestWithBody(method, path, body)
  816. if method == "POST" {
  817. req.Header.Add("Content-Type", MIMEPOSTForm)
  818. }
  819. err := b.Bind(req, &obj)
  820. assert.NoError(t, err)
  821. assert.Equal(t, "bar", obj.Foo)
  822. assert.Equal(t, "foo", obj.Bar)
  823. }
  824. func testQueryBindingFail(t *testing.T, method, path, badPath, body, badBody string) {
  825. b := Query
  826. assert.Equal(t, "query", b.Name())
  827. obj := FooStructForMapType{}
  828. req := requestWithBody(method, path, body)
  829. if method == "POST" {
  830. req.Header.Add("Content-Type", MIMEPOSTForm)
  831. }
  832. err := b.Bind(req, &obj)
  833. assert.Error(t, err)
  834. }
  835. func testQueryBindingBoolFail(t *testing.T, method, path, badPath, body, badBody string) {
  836. b := Query
  837. assert.Equal(t, "query", b.Name())
  838. obj := FooStructForBoolType{}
  839. req := requestWithBody(method, path, body)
  840. if method == "POST" {
  841. req.Header.Add("Content-Type", MIMEPOSTForm)
  842. }
  843. err := b.Bind(req, &obj)
  844. assert.Error(t, err)
  845. }
  846. func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
  847. assert.Equal(t, name, b.Name())
  848. obj := FooStruct{}
  849. req := requestWithBody("POST", path, body)
  850. err := b.Bind(req, &obj)
  851. assert.NoError(t, err)
  852. assert.Equal(t, "bar", obj.Foo)
  853. obj = FooStruct{}
  854. req = requestWithBody("POST", badPath, badBody)
  855. err = JSON.Bind(req, &obj)
  856. assert.Error(t, err)
  857. }
  858. func testBodyBindingUseNumber(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
  859. assert.Equal(t, name, b.Name())
  860. obj := FooStructUseNumber{}
  861. req := requestWithBody("POST", path, body)
  862. EnableDecoderUseNumber = true
  863. err := b.Bind(req, &obj)
  864. assert.NoError(t, err)
  865. // we hope it is int64(123)
  866. v, e := obj.Foo.(json.Number).Int64()
  867. assert.NoError(t, e)
  868. assert.Equal(t, int64(123), v)
  869. obj = FooStructUseNumber{}
  870. req = requestWithBody("POST", badPath, badBody)
  871. err = JSON.Bind(req, &obj)
  872. assert.Error(t, err)
  873. }
  874. func testBodyBindingUseNumber2(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
  875. assert.Equal(t, name, b.Name())
  876. obj := FooStructUseNumber{}
  877. req := requestWithBody("POST", path, body)
  878. EnableDecoderUseNumber = false
  879. err := b.Bind(req, &obj)
  880. assert.NoError(t, err)
  881. // it will return float64(123) if not use EnableDecoderUseNumber
  882. // maybe it is not hoped
  883. assert.Equal(t, float64(123), obj.Foo)
  884. obj = FooStructUseNumber{}
  885. req = requestWithBody("POST", badPath, badBody)
  886. err = JSON.Bind(req, &obj)
  887. assert.Error(t, err)
  888. }
  889. func testBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
  890. assert.Equal(t, name, b.Name())
  891. obj := FooStruct{}
  892. req := requestWithBody("POST", path, body)
  893. err := b.Bind(req, &obj)
  894. assert.Error(t, err)
  895. assert.Equal(t, "", obj.Foo)
  896. obj = FooStruct{}
  897. req = requestWithBody("POST", badPath, badBody)
  898. err = JSON.Bind(req, &obj)
  899. assert.Error(t, err)
  900. }
  901. func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
  902. assert.Equal(t, name, b.Name())
  903. obj := protoexample.Test{}
  904. req := requestWithBody("POST", path, body)
  905. req.Header.Add("Content-Type", MIMEPROTOBUF)
  906. err := b.Bind(req, &obj)
  907. assert.NoError(t, err)
  908. assert.Equal(t, "yes", *obj.Label)
  909. obj = protoexample.Test{}
  910. req = requestWithBody("POST", badPath, badBody)
  911. req.Header.Add("Content-Type", MIMEPROTOBUF)
  912. err = ProtoBuf.Bind(req, &obj)
  913. assert.Error(t, err)
  914. }
  915. type hook struct{}
  916. func (h hook) Read([]byte) (int, error) {
  917. return 0, errors.New("error")
  918. }
  919. func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
  920. assert.Equal(t, name, b.Name())
  921. obj := protoexample.Test{}
  922. req := requestWithBody("POST", path, body)
  923. req.Body = ioutil.NopCloser(&hook{})
  924. req.Header.Add("Content-Type", MIMEPROTOBUF)
  925. err := b.Bind(req, &obj)
  926. assert.Error(t, err)
  927. obj = protoexample.Test{}
  928. req = requestWithBody("POST", badPath, badBody)
  929. req.Header.Add("Content-Type", MIMEPROTOBUF)
  930. err = ProtoBuf.Bind(req, &obj)
  931. assert.Error(t, err)
  932. }
  933. func testMsgPackBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
  934. assert.Equal(t, name, b.Name())
  935. obj := FooStruct{}
  936. req := requestWithBody("POST", path, body)
  937. req.Header.Add("Content-Type", MIMEMSGPACK)
  938. err := b.Bind(req, &obj)
  939. assert.NoError(t, err)
  940. assert.Equal(t, "bar", obj.Foo)
  941. obj = FooStruct{}
  942. req = requestWithBody("POST", badPath, badBody)
  943. req.Header.Add("Content-Type", MIMEMSGPACK)
  944. err = MsgPack.Bind(req, &obj)
  945. assert.Error(t, err)
  946. }
  947. func requestWithBody(method, path, body string) (req *http.Request) {
  948. req, _ = http.NewRequest(method, path, bytes.NewBufferString(body))
  949. return
  950. }