github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/gin/binding/binding_test.go (about)

     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  
     5  package binding
     6  
     7  import (
     8  	"bytes"
     9  	"encoding/json"
    10  	"errors"
    11  	"io"
    12  	"io/ioutil"
    13  	"mime/multipart"
    14  	"github.com/hellobchain/newcryptosm/http"
    15  	"os"
    16  	"reflect"
    17  	"strconv"
    18  	"strings"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/golang/protobuf/proto"
    23  	"github.com/stretchr/testify/assert"
    24  	"github.com/hellobchain/third_party/gin/testdata/protoexample"
    25  )
    26  
    27  type appkey struct {
    28  	Appkey string `json:"appkey" form:"appkey"`
    29  }
    30  
    31  type QueryTest struct {
    32  	Page int `json:"page" form:"page"`
    33  	Size int `json:"size" form:"size"`
    34  	appkey
    35  }
    36  
    37  type FooStruct struct {
    38  	Foo string `msgpack:"foo" json:"foo" form:"foo" xml:"foo" binding:"required,max=32"`
    39  }
    40  
    41  type FooBarStruct struct {
    42  	FooStruct
    43  	Bar string `msgpack:"bar" json:"bar" form:"bar" xml:"bar" binding:"required"`
    44  }
    45  
    46  type FooBarFileStruct struct {
    47  	FooBarStruct
    48  	File *multipart.FileHeader `form:"file" binding:"required"`
    49  }
    50  
    51  type FooBarFileFailStruct struct {
    52  	FooBarStruct
    53  	File *multipart.FileHeader `invalid_name:"file" binding:"required"`
    54  	// for unexport test
    55  	data *multipart.FileHeader `form:"data" binding:"required"`
    56  }
    57  
    58  type FooDefaultBarStruct struct {
    59  	FooStruct
    60  	Bar string `msgpack:"bar" json:"bar" form:"bar,default=hello" xml:"bar" binding:"required"`
    61  }
    62  
    63  type FooStructUseNumber struct {
    64  	Foo interface{} `json:"foo" binding:"required"`
    65  }
    66  
    67  type FooStructDisallowUnknownFields struct {
    68  	Foo interface{} `json:"foo" binding:"required"`
    69  }
    70  
    71  type FooBarStructForTimeType struct {
    72  	TimeFoo    time.Time `form:"time_foo" time_format:"2006-01-02" time_utc:"1" time_location:"Asia/Chongqing"`
    73  	TimeBar    time.Time `form:"time_bar" time_format:"2006-01-02" time_utc:"1"`
    74  	CreateTime time.Time `form:"createTime" time_format:"unixNano"`
    75  	UnixTime   time.Time `form:"unixTime" time_format:"unix"`
    76  }
    77  
    78  type FooStructForTimeTypeNotUnixFormat struct {
    79  	CreateTime time.Time `form:"createTime" time_format:"unixNano"`
    80  	UnixTime   time.Time `form:"unixTime" time_format:"unix"`
    81  }
    82  
    83  type FooStructForTimeTypeNotFormat struct {
    84  	TimeFoo time.Time `form:"time_foo"`
    85  }
    86  
    87  type FooStructForTimeTypeFailFormat struct {
    88  	TimeFoo time.Time `form:"time_foo" time_format:"2017-11-15"`
    89  }
    90  
    91  type FooStructForTimeTypeFailLocation struct {
    92  	TimeFoo time.Time `form:"time_foo" time_format:"2006-01-02" time_location:"/asia/chongqing"`
    93  }
    94  
    95  type FooStructForMapType struct {
    96  	MapFoo map[string]interface{} `form:"map_foo"`
    97  }
    98  
    99  type FooStructForIgnoreFormTag struct {
   100  	Foo *string `form:"-"`
   101  }
   102  
   103  type InvalidNameType struct {
   104  	TestName string `invalid_name:"test_name"`
   105  }
   106  
   107  type InvalidNameMapType struct {
   108  	TestName struct {
   109  		MapFoo map[string]interface{} `form:"map_foo"`
   110  	}
   111  }
   112  
   113  type FooStructForSliceType struct {
   114  	SliceFoo []int `form:"slice_foo"`
   115  }
   116  
   117  type FooStructForStructType struct {
   118  	StructFoo struct {
   119  		Idx int `form:"idx"`
   120  	}
   121  }
   122  
   123  type FooStructForStructPointerType struct {
   124  	StructPointerFoo *struct {
   125  		Name string `form:"name"`
   126  	}
   127  }
   128  
   129  type FooStructForSliceMapType struct {
   130  	// Unknown type: not support map
   131  	SliceMapFoo []map[string]interface{} `form:"slice_map_foo"`
   132  }
   133  
   134  type FooStructForBoolType struct {
   135  	BoolFoo bool `form:"bool_foo"`
   136  }
   137  
   138  type FooStructForStringPtrType struct {
   139  	PtrFoo *string `form:"ptr_foo"`
   140  	PtrBar *string `form:"ptr_bar" binding:"required"`
   141  }
   142  
   143  type FooStructForMapPtrType struct {
   144  	PtrBar *map[string]interface{} `form:"ptr_bar"`
   145  }
   146  
   147  func TestBindingDefault(t *testing.T) {
   148  	assert.Equal(t, Form, Default("GET", ""))
   149  	assert.Equal(t, Form, Default("GET", MIMEJSON))
   150  
   151  	assert.Equal(t, JSON, Default("POST", MIMEJSON))
   152  	assert.Equal(t, JSON, Default("PUT", MIMEJSON))
   153  
   154  	assert.Equal(t, XML, Default("POST", MIMEXML))
   155  	assert.Equal(t, XML, Default("PUT", MIMEXML2))
   156  
   157  	assert.Equal(t, Form, Default("POST", MIMEPOSTForm))
   158  	assert.Equal(t, Form, Default("PUT", MIMEPOSTForm))
   159  
   160  	assert.Equal(t, FormMultipart, Default("POST", MIMEMultipartPOSTForm))
   161  	assert.Equal(t, FormMultipart, Default("PUT", MIMEMultipartPOSTForm))
   162  
   163  	assert.Equal(t, ProtoBuf, Default("POST", MIMEPROTOBUF))
   164  	assert.Equal(t, ProtoBuf, Default("PUT", MIMEPROTOBUF))
   165  
   166  	assert.Equal(t, YAML, Default("POST", MIMEYAML))
   167  	assert.Equal(t, YAML, Default("PUT", MIMEYAML))
   168  }
   169  
   170  func TestBindingJSONNilBody(t *testing.T) {
   171  	var obj FooStruct
   172  	req, _ := http.NewRequest(http.MethodPost, "/", nil)
   173  	err := JSON.Bind(req, &obj)
   174  	assert.Error(t, err)
   175  }
   176  
   177  func TestBindingJSON(t *testing.T) {
   178  	testBodyBinding(t,
   179  		JSON, "json",
   180  		"/", "/",
   181  		`{"foo": "bar"}`, `{"bar": "foo"}`)
   182  }
   183  
   184  func TestBindingJSONSlice(t *testing.T) {
   185  	EnableDecoderDisallowUnknownFields = true
   186  	defer func() {
   187  		EnableDecoderDisallowUnknownFields = false
   188  	}()
   189  
   190  	testBodyBindingSlice(t, JSON, "json", "/", "/", `[]`, ``)
   191  	testBodyBindingSlice(t, JSON, "json", "/", "/", `[{"foo": "123"}]`, `[{}]`)
   192  	testBodyBindingSlice(t, JSON, "json", "/", "/", `[{"foo": "123"}]`, `[{"foo": ""}]`)
   193  	testBodyBindingSlice(t, JSON, "json", "/", "/", `[{"foo": "123"}]`, `[{"foo": 123}]`)
   194  	testBodyBindingSlice(t, JSON, "json", "/", "/", `[{"foo": "123"}]`, `[{"bar": 123}]`)
   195  	testBodyBindingSlice(t, JSON, "json", "/", "/", `[{"foo": "123"}]`, `[{"foo": "123456789012345678901234567890123"}]`)
   196  }
   197  
   198  func TestBindingJSONUseNumber(t *testing.T) {
   199  	testBodyBindingUseNumber(t,
   200  		JSON, "json",
   201  		"/", "/",
   202  		`{"foo": 123}`, `{"bar": "foo"}`)
   203  }
   204  
   205  func TestBindingJSONUseNumber2(t *testing.T) {
   206  	testBodyBindingUseNumber2(t,
   207  		JSON, "json",
   208  		"/", "/",
   209  		`{"foo": 123}`, `{"bar": "foo"}`)
   210  }
   211  
   212  func TestBindingJSONDisallowUnknownFields(t *testing.T) {
   213  	testBodyBindingDisallowUnknownFields(t, JSON,
   214  		"/", "/",
   215  		`{"foo": "bar"}`, `{"foo": "bar", "what": "this"}`)
   216  }
   217  
   218  func TestBindingJSONStringMap(t *testing.T) {
   219  	testBodyBindingStringMap(t, JSON,
   220  		"/", "/",
   221  		`{"foo": "bar", "hello": "world"}`, `{"num": 2}`)
   222  }
   223  
   224  func TestBindingForm(t *testing.T) {
   225  	testFormBinding(t, "POST",
   226  		"/", "/",
   227  		"foo=bar&bar=foo", "bar2=foo")
   228  }
   229  
   230  func TestBindingForm2(t *testing.T) {
   231  	testFormBinding(t, "GET",
   232  		"/?foo=bar&bar=foo", "/?bar2=foo",
   233  		"", "")
   234  }
   235  
   236  func TestBindingFormEmbeddedStruct(t *testing.T) {
   237  	testFormBindingEmbeddedStruct(t, "POST",
   238  		"/", "/",
   239  		"page=1&size=2&appkey=test-appkey", "bar2=foo")
   240  }
   241  
   242  func TestBindingFormEmbeddedStruct2(t *testing.T) {
   243  	testFormBindingEmbeddedStruct(t, "GET",
   244  		"/?page=1&size=2&appkey=test-appkey", "/?bar2=foo",
   245  		"", "")
   246  }
   247  
   248  func TestBindingFormDefaultValue(t *testing.T) {
   249  	testFormBindingDefaultValue(t, "POST",
   250  		"/", "/",
   251  		"foo=bar", "bar2=foo")
   252  }
   253  
   254  func TestBindingFormDefaultValue2(t *testing.T) {
   255  	testFormBindingDefaultValue(t, "GET",
   256  		"/?foo=bar", "/?bar2=foo",
   257  		"", "")
   258  }
   259  
   260  func TestBindingFormForTime(t *testing.T) {
   261  	testFormBindingForTime(t, "POST",
   262  		"/", "/",
   263  		"time_foo=2017-11-15&time_bar=&createTime=1562400033000000123&unixTime=1562400033", "bar2=foo")
   264  	testFormBindingForTimeNotUnixFormat(t, "POST",
   265  		"/", "/",
   266  		"time_foo=2017-11-15&createTime=bad&unixTime=bad", "bar2=foo")
   267  	testFormBindingForTimeNotFormat(t, "POST",
   268  		"/", "/",
   269  		"time_foo=2017-11-15", "bar2=foo")
   270  	testFormBindingForTimeFailFormat(t, "POST",
   271  		"/", "/",
   272  		"time_foo=2017-11-15", "bar2=foo")
   273  	testFormBindingForTimeFailLocation(t, "POST",
   274  		"/", "/",
   275  		"time_foo=2017-11-15", "bar2=foo")
   276  }
   277  
   278  func TestBindingFormForTime2(t *testing.T) {
   279  	testFormBindingForTime(t, "GET",
   280  		"/?time_foo=2017-11-15&time_bar=&createTime=1562400033000000123&unixTime=1562400033", "/?bar2=foo",
   281  		"", "")
   282  	testFormBindingForTimeNotUnixFormat(t, "POST",
   283  		"/", "/",
   284  		"time_foo=2017-11-15&createTime=bad&unixTime=bad", "bar2=foo")
   285  	testFormBindingForTimeNotFormat(t, "GET",
   286  		"/?time_foo=2017-11-15", "/?bar2=foo",
   287  		"", "")
   288  	testFormBindingForTimeFailFormat(t, "GET",
   289  		"/?time_foo=2017-11-15", "/?bar2=foo",
   290  		"", "")
   291  	testFormBindingForTimeFailLocation(t, "GET",
   292  		"/?time_foo=2017-11-15", "/?bar2=foo",
   293  		"", "")
   294  }
   295  
   296  func TestFormBindingIgnoreField(t *testing.T) {
   297  	testFormBindingIgnoreField(t, "POST",
   298  		"/", "/",
   299  		"-=bar", "")
   300  }
   301  
   302  func TestBindingFormInvalidName(t *testing.T) {
   303  	testFormBindingInvalidName(t, "POST",
   304  		"/", "/",
   305  		"test_name=bar", "bar2=foo")
   306  }
   307  
   308  func TestBindingFormInvalidName2(t *testing.T) {
   309  	testFormBindingInvalidName2(t, "POST",
   310  		"/", "/",
   311  		"map_foo=bar", "bar2=foo")
   312  }
   313  
   314  func TestBindingFormForType(t *testing.T) {
   315  	testFormBindingForType(t, "POST",
   316  		"/", "/",
   317  		"map_foo={\"bar\":123}", "map_foo=1", "Map")
   318  
   319  	testFormBindingForType(t, "POST",
   320  		"/", "/",
   321  		"slice_foo=1&slice_foo=2", "bar2=1&bar2=2", "Slice")
   322  
   323  	testFormBindingForType(t, "GET",
   324  		"/?slice_foo=1&slice_foo=2", "/?bar2=1&bar2=2",
   325  		"", "", "Slice")
   326  
   327  	testFormBindingForType(t, "POST",
   328  		"/", "/",
   329  		"slice_map_foo=1&slice_map_foo=2", "bar2=1&bar2=2", "SliceMap")
   330  
   331  	testFormBindingForType(t, "GET",
   332  		"/?slice_map_foo=1&slice_map_foo=2", "/?bar2=1&bar2=2",
   333  		"", "", "SliceMap")
   334  
   335  	testFormBindingForType(t, "POST",
   336  		"/", "/",
   337  		"ptr_bar=test", "bar2=test", "Ptr")
   338  
   339  	testFormBindingForType(t, "GET",
   340  		"/?ptr_bar=test", "/?bar2=test",
   341  		"", "", "Ptr")
   342  
   343  	testFormBindingForType(t, "POST",
   344  		"/", "/",
   345  		"idx=123", "id1=1", "Struct")
   346  
   347  	testFormBindingForType(t, "GET",
   348  		"/?idx=123", "/?id1=1",
   349  		"", "", "Struct")
   350  
   351  	testFormBindingForType(t, "POST",
   352  		"/", "/",
   353  		"name=thinkerou", "name1=ou", "StructPointer")
   354  
   355  	testFormBindingForType(t, "GET",
   356  		"/?name=thinkerou", "/?name1=ou",
   357  		"", "", "StructPointer")
   358  }
   359  
   360  func TestBindingFormStringMap(t *testing.T) {
   361  	testBodyBindingStringMap(t, Form,
   362  		"/", "",
   363  		`foo=bar&hello=world`, "")
   364  	// Should pick the last value
   365  	testBodyBindingStringMap(t, Form,
   366  		"/", "",
   367  		`foo=something&foo=bar&hello=world`, "")
   368  }
   369  
   370  func TestBindingFormStringSliceMap(t *testing.T) {
   371  	obj := make(map[string][]string)
   372  	req := requestWithBody("POST", "/", "foo=something&foo=bar&hello=world")
   373  	req.Header.Add("Content-Type", MIMEPOSTForm)
   374  	err := Form.Bind(req, &obj)
   375  	assert.NoError(t, err)
   376  	assert.NotNil(t, obj)
   377  	assert.Len(t, obj, 2)
   378  	target := map[string][]string{
   379  		"foo":   {"something", "bar"},
   380  		"hello": {"world"},
   381  	}
   382  	assert.True(t, reflect.DeepEqual(obj, target))
   383  
   384  	objInvalid := make(map[string][]int)
   385  	req = requestWithBody("POST", "/", "foo=something&foo=bar&hello=world")
   386  	req.Header.Add("Content-Type", MIMEPOSTForm)
   387  	err = Form.Bind(req, &objInvalid)
   388  	assert.Error(t, err)
   389  }
   390  
   391  func TestBindingQuery(t *testing.T) {
   392  	testQueryBinding(t, "POST",
   393  		"/?foo=bar&bar=foo", "/",
   394  		"foo=unused", "bar2=foo")
   395  }
   396  
   397  func TestBindingQuery2(t *testing.T) {
   398  	testQueryBinding(t, "GET",
   399  		"/?foo=bar&bar=foo", "/?bar2=foo",
   400  		"foo=unused", "")
   401  }
   402  
   403  func TestBindingQueryFail(t *testing.T) {
   404  	testQueryBindingFail(t, "POST",
   405  		"/?map_foo=", "/",
   406  		"map_foo=unused", "bar2=foo")
   407  }
   408  
   409  func TestBindingQueryFail2(t *testing.T) {
   410  	testQueryBindingFail(t, "GET",
   411  		"/?map_foo=", "/?bar2=foo",
   412  		"map_foo=unused", "")
   413  }
   414  
   415  func TestBindingQueryBoolFail(t *testing.T) {
   416  	testQueryBindingBoolFail(t, "GET",
   417  		"/?bool_foo=fasl", "/?bar2=foo",
   418  		"bool_foo=unused", "")
   419  }
   420  
   421  func TestBindingQueryStringMap(t *testing.T) {
   422  	b := Query
   423  
   424  	obj := make(map[string]string)
   425  	req := requestWithBody("GET", "/?foo=bar&hello=world", "")
   426  	err := b.Bind(req, &obj)
   427  	assert.NoError(t, err)
   428  	assert.NotNil(t, obj)
   429  	assert.Len(t, obj, 2)
   430  	assert.Equal(t, "bar", obj["foo"])
   431  	assert.Equal(t, "world", obj["hello"])
   432  
   433  	obj = make(map[string]string)
   434  	req = requestWithBody("GET", "/?foo=bar&foo=2&hello=world", "") // should pick last
   435  	err = b.Bind(req, &obj)
   436  	assert.NoError(t, err)
   437  	assert.NotNil(t, obj)
   438  	assert.Len(t, obj, 2)
   439  	assert.Equal(t, "2", obj["foo"])
   440  	assert.Equal(t, "world", obj["hello"])
   441  }
   442  
   443  func TestBindingXML(t *testing.T) {
   444  	testBodyBinding(t,
   445  		XML, "xml",
   446  		"/", "/",
   447  		"<map><foo>bar</foo></map>", "<map><bar>foo</bar></map>")
   448  }
   449  
   450  func TestBindingXMLFail(t *testing.T) {
   451  	testBodyBindingFail(t,
   452  		XML, "xml",
   453  		"/", "/",
   454  		"<map><foo>bar<foo></map>", "<map><bar>foo</bar></map>")
   455  }
   456  
   457  func TestBindingYAML(t *testing.T) {
   458  	testBodyBinding(t,
   459  		YAML, "yaml",
   460  		"/", "/",
   461  		`foo: bar`, `bar: foo`)
   462  }
   463  
   464  func TestBindingYAMLStringMap(t *testing.T) {
   465  	// YAML is a superset of JSON, so the test below is JSON (to avoid newlines)
   466  	testBodyBindingStringMap(t, YAML,
   467  		"/", "/",
   468  		`{"foo": "bar", "hello": "world"}`, `{"nested": {"foo": "bar"}}`)
   469  }
   470  
   471  func TestBindingYAMLFail(t *testing.T) {
   472  	testBodyBindingFail(t,
   473  		YAML, "yaml",
   474  		"/", "/",
   475  		`foo:\nbar`, `bar: foo`)
   476  }
   477  
   478  func createFormPostRequest(t *testing.T) *http.Request {
   479  	req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar&bar=foo"))
   480  	assert.NoError(t, err)
   481  	req.Header.Set("Content-Type", MIMEPOSTForm)
   482  	return req
   483  }
   484  
   485  func createDefaultFormPostRequest(t *testing.T) *http.Request {
   486  	req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", bytes.NewBufferString("foo=bar"))
   487  	assert.NoError(t, err)
   488  	req.Header.Set("Content-Type", MIMEPOSTForm)
   489  	return req
   490  }
   491  
   492  func createFormPostRequestForMap(t *testing.T) *http.Request {
   493  	req, err := http.NewRequest("POST", "/?map_foo=getfoo", bytes.NewBufferString("map_foo={\"bar\":123}"))
   494  	assert.NoError(t, err)
   495  	req.Header.Set("Content-Type", MIMEPOSTForm)
   496  	return req
   497  }
   498  
   499  func createFormPostRequestForMapFail(t *testing.T) *http.Request {
   500  	req, err := http.NewRequest("POST", "/?map_foo=getfoo", bytes.NewBufferString("map_foo=hello"))
   501  	assert.NoError(t, err)
   502  	req.Header.Set("Content-Type", MIMEPOSTForm)
   503  	return req
   504  }
   505  
   506  func createFormFilesMultipartRequest(t *testing.T) *http.Request {
   507  	boundary := "--testboundary"
   508  	body := new(bytes.Buffer)
   509  	mw := multipart.NewWriter(body)
   510  	defer mw.Close()
   511  
   512  	assert.NoError(t, mw.SetBoundary(boundary))
   513  	assert.NoError(t, mw.WriteField("foo", "bar"))
   514  	assert.NoError(t, mw.WriteField("bar", "foo"))
   515  
   516  	f, err := os.Open("form.go")
   517  	assert.NoError(t, err)
   518  	defer f.Close()
   519  	fw, err1 := mw.CreateFormFile("file", "form.go")
   520  	assert.NoError(t, err1)
   521  	_, err = io.Copy(fw, f)
   522  	assert.NoError(t, err)
   523  
   524  	req, err2 := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
   525  	assert.NoError(t, err2)
   526  	req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
   527  
   528  	return req
   529  }
   530  
   531  func createFormFilesMultipartRequestFail(t *testing.T) *http.Request {
   532  	boundary := "--testboundary"
   533  	body := new(bytes.Buffer)
   534  	mw := multipart.NewWriter(body)
   535  	defer mw.Close()
   536  
   537  	assert.NoError(t, mw.SetBoundary(boundary))
   538  	assert.NoError(t, mw.WriteField("foo", "bar"))
   539  	assert.NoError(t, mw.WriteField("bar", "foo"))
   540  
   541  	f, err := os.Open("form.go")
   542  	assert.NoError(t, err)
   543  	defer f.Close()
   544  	fw, err1 := mw.CreateFormFile("file_foo", "form_foo.go")
   545  	assert.NoError(t, err1)
   546  	_, err = io.Copy(fw, f)
   547  	assert.NoError(t, err)
   548  
   549  	req, err2 := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
   550  	assert.NoError(t, err2)
   551  	req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
   552  
   553  	return req
   554  }
   555  
   556  func createFormMultipartRequest(t *testing.T) *http.Request {
   557  	boundary := "--testboundary"
   558  	body := new(bytes.Buffer)
   559  	mw := multipart.NewWriter(body)
   560  	defer mw.Close()
   561  
   562  	assert.NoError(t, mw.SetBoundary(boundary))
   563  	assert.NoError(t, mw.WriteField("foo", "bar"))
   564  	assert.NoError(t, mw.WriteField("bar", "foo"))
   565  	req, err := http.NewRequest("POST", "/?foo=getfoo&bar=getbar", body)
   566  	assert.NoError(t, err)
   567  	req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
   568  	return req
   569  }
   570  
   571  func createFormMultipartRequestForMap(t *testing.T) *http.Request {
   572  	boundary := "--testboundary"
   573  	body := new(bytes.Buffer)
   574  	mw := multipart.NewWriter(body)
   575  	defer mw.Close()
   576  
   577  	assert.NoError(t, mw.SetBoundary(boundary))
   578  	assert.NoError(t, mw.WriteField("map_foo", "{\"bar\":123, \"name\":\"thinkerou\", \"pai\": 3.14}"))
   579  	req, err := http.NewRequest("POST", "/?map_foo=getfoo", body)
   580  	assert.NoError(t, err)
   581  	req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
   582  	return req
   583  }
   584  
   585  func createFormMultipartRequestForMapFail(t *testing.T) *http.Request {
   586  	boundary := "--testboundary"
   587  	body := new(bytes.Buffer)
   588  	mw := multipart.NewWriter(body)
   589  	defer mw.Close()
   590  
   591  	assert.NoError(t, mw.SetBoundary(boundary))
   592  	assert.NoError(t, mw.WriteField("map_foo", "3.14"))
   593  	req, err := http.NewRequest("POST", "/?map_foo=getfoo", body)
   594  	assert.NoError(t, err)
   595  	req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+boundary)
   596  	return req
   597  }
   598  
   599  func TestBindingFormPost(t *testing.T) {
   600  	req := createFormPostRequest(t)
   601  	var obj FooBarStruct
   602  	assert.NoError(t, FormPost.Bind(req, &obj))
   603  
   604  	assert.Equal(t, "form-urlencoded", FormPost.Name())
   605  	assert.Equal(t, "bar", obj.Foo)
   606  	assert.Equal(t, "foo", obj.Bar)
   607  }
   608  
   609  func TestBindingDefaultValueFormPost(t *testing.T) {
   610  	req := createDefaultFormPostRequest(t)
   611  	var obj FooDefaultBarStruct
   612  	assert.NoError(t, FormPost.Bind(req, &obj))
   613  
   614  	assert.Equal(t, "bar", obj.Foo)
   615  	assert.Equal(t, "hello", obj.Bar)
   616  }
   617  
   618  func TestBindingFormPostForMap(t *testing.T) {
   619  	req := createFormPostRequestForMap(t)
   620  	var obj FooStructForMapType
   621  	err := FormPost.Bind(req, &obj)
   622  	assert.NoError(t, err)
   623  	assert.Equal(t, float64(123), obj.MapFoo["bar"].(float64))
   624  }
   625  
   626  func TestBindingFormPostForMapFail(t *testing.T) {
   627  	req := createFormPostRequestForMapFail(t)
   628  	var obj FooStructForMapType
   629  	err := FormPost.Bind(req, &obj)
   630  	assert.Error(t, err)
   631  }
   632  
   633  func TestBindingFormFilesMultipart(t *testing.T) {
   634  	req := createFormFilesMultipartRequest(t)
   635  	var obj FooBarFileStruct
   636  	err := FormMultipart.Bind(req, &obj)
   637  	assert.NoError(t, err)
   638  
   639  	// file from os
   640  	f, _ := os.Open("form.go")
   641  	defer f.Close()
   642  	fileActual, _ := ioutil.ReadAll(f)
   643  
   644  	// file from multipart
   645  	mf, _ := obj.File.Open()
   646  	defer mf.Close()
   647  	fileExpect, _ := ioutil.ReadAll(mf)
   648  
   649  	assert.Equal(t, FormMultipart.Name(), "multipart/form-data")
   650  	assert.Equal(t, obj.Foo, "bar")
   651  	assert.Equal(t, obj.Bar, "foo")
   652  	assert.Equal(t, fileExpect, fileActual)
   653  }
   654  
   655  func TestBindingFormFilesMultipartFail(t *testing.T) {
   656  	req := createFormFilesMultipartRequestFail(t)
   657  	var obj FooBarFileFailStruct
   658  	err := FormMultipart.Bind(req, &obj)
   659  	assert.Error(t, err)
   660  }
   661  
   662  func TestBindingFormMultipart(t *testing.T) {
   663  	req := createFormMultipartRequest(t)
   664  	var obj FooBarStruct
   665  	assert.NoError(t, FormMultipart.Bind(req, &obj))
   666  
   667  	assert.Equal(t, "multipart/form-data", FormMultipart.Name())
   668  	assert.Equal(t, "bar", obj.Foo)
   669  	assert.Equal(t, "foo", obj.Bar)
   670  }
   671  
   672  func TestBindingFormMultipartForMap(t *testing.T) {
   673  	req := createFormMultipartRequestForMap(t)
   674  	var obj FooStructForMapType
   675  	err := FormMultipart.Bind(req, &obj)
   676  	assert.NoError(t, err)
   677  	assert.Equal(t, float64(123), obj.MapFoo["bar"].(float64))
   678  	assert.Equal(t, "thinkerou", obj.MapFoo["name"].(string))
   679  	assert.Equal(t, float64(3.14), obj.MapFoo["pai"].(float64))
   680  }
   681  
   682  func TestBindingFormMultipartForMapFail(t *testing.T) {
   683  	req := createFormMultipartRequestForMapFail(t)
   684  	var obj FooStructForMapType
   685  	err := FormMultipart.Bind(req, &obj)
   686  	assert.Error(t, err)
   687  }
   688  
   689  func TestBindingProtoBuf(t *testing.T) {
   690  	test := &protoexample.Test{
   691  		Label: proto.String("yes"),
   692  	}
   693  	data, _ := proto.Marshal(test)
   694  
   695  	testProtoBodyBinding(t,
   696  		ProtoBuf, "protobuf",
   697  		"/", "/",
   698  		string(data), string(data[1:]))
   699  }
   700  
   701  func TestBindingProtoBufFail(t *testing.T) {
   702  	test := &protoexample.Test{
   703  		Label: proto.String("yes"),
   704  	}
   705  	data, _ := proto.Marshal(test)
   706  
   707  	testProtoBodyBindingFail(t,
   708  		ProtoBuf, "protobuf",
   709  		"/", "/",
   710  		string(data), string(data[1:]))
   711  }
   712  
   713  func TestValidationFails(t *testing.T) {
   714  	var obj FooStruct
   715  	req := requestWithBody("POST", "/", `{"bar": "foo"}`)
   716  	err := JSON.Bind(req, &obj)
   717  	assert.Error(t, err)
   718  }
   719  
   720  func TestValidationDisabled(t *testing.T) {
   721  	backup := Validator
   722  	Validator = nil
   723  	defer func() { Validator = backup }()
   724  
   725  	var obj FooStruct
   726  	req := requestWithBody("POST", "/", `{"bar": "foo"}`)
   727  	err := JSON.Bind(req, &obj)
   728  	assert.NoError(t, err)
   729  }
   730  
   731  func TestRequiredSucceeds(t *testing.T) {
   732  	type HogeStruct struct {
   733  		Hoge *int `json:"hoge" binding:"required"`
   734  	}
   735  
   736  	var obj HogeStruct
   737  	req := requestWithBody("POST", "/", `{"hoge": 0}`)
   738  	err := JSON.Bind(req, &obj)
   739  	assert.NoError(t, err)
   740  }
   741  
   742  func TestRequiredFails(t *testing.T) {
   743  	type HogeStruct struct {
   744  		Hoge *int `json:"foo" binding:"required"`
   745  	}
   746  
   747  	var obj HogeStruct
   748  	req := requestWithBody("POST", "/", `{"boen": 0}`)
   749  	err := JSON.Bind(req, &obj)
   750  	assert.Error(t, err)
   751  }
   752  
   753  func TestHeaderBinding(t *testing.T) {
   754  	h := Header
   755  	assert.Equal(t, "header", h.Name())
   756  
   757  	type tHeader struct {
   758  		Limit int `header:"limit"`
   759  	}
   760  
   761  	var theader tHeader
   762  	req := requestWithBody("GET", "/", "")
   763  	req.Header.Add("limit", "1000")
   764  	assert.NoError(t, h.Bind(req, &theader))
   765  	assert.Equal(t, 1000, theader.Limit)
   766  
   767  	req = requestWithBody("GET", "/", "")
   768  	req.Header.Add("fail", `{fail:fail}`)
   769  
   770  	type failStruct struct {
   771  		Fail map[string]interface{} `header:"fail"`
   772  	}
   773  
   774  	err := h.Bind(req, &failStruct{})
   775  	assert.Error(t, err)
   776  }
   777  
   778  func TestUriBinding(t *testing.T) {
   779  	b := Uri
   780  	assert.Equal(t, "uri", b.Name())
   781  
   782  	type Tag struct {
   783  		Name string `uri:"name"`
   784  	}
   785  	var tag Tag
   786  	m := make(map[string][]string)
   787  	m["name"] = []string{"thinkerou"}
   788  	assert.NoError(t, b.BindUri(m, &tag))
   789  	assert.Equal(t, "thinkerou", tag.Name)
   790  
   791  	type NotSupportStruct struct {
   792  		Name map[string]interface{} `uri:"name"`
   793  	}
   794  	var not NotSupportStruct
   795  	assert.Error(t, b.BindUri(m, &not))
   796  	assert.Equal(t, map[string]interface{}(nil), not.Name)
   797  }
   798  
   799  func TestUriInnerBinding(t *testing.T) {
   800  	type Tag struct {
   801  		Name string `uri:"name"`
   802  		S    struct {
   803  			Age int `uri:"age"`
   804  		}
   805  	}
   806  
   807  	expectedName := "mike"
   808  	expectedAge := 25
   809  
   810  	m := map[string][]string{
   811  		"name": {expectedName},
   812  		"age":  {strconv.Itoa(expectedAge)},
   813  	}
   814  
   815  	var tag Tag
   816  	assert.NoError(t, Uri.BindUri(m, &tag))
   817  	assert.Equal(t, tag.Name, expectedName)
   818  	assert.Equal(t, tag.S.Age, expectedAge)
   819  }
   820  
   821  func testFormBindingEmbeddedStruct(t *testing.T, method, path, badPath, body, badBody string) {
   822  	b := Form
   823  	assert.Equal(t, "form", b.Name())
   824  
   825  	obj := QueryTest{}
   826  	req := requestWithBody(method, path, body)
   827  	if method == "POST" {
   828  		req.Header.Add("Content-Type", MIMEPOSTForm)
   829  	}
   830  	err := b.Bind(req, &obj)
   831  	assert.NoError(t, err)
   832  	assert.Equal(t, 1, obj.Page)
   833  	assert.Equal(t, 2, obj.Size)
   834  	assert.Equal(t, "test-appkey", obj.Appkey)
   835  
   836  }
   837  
   838  func testFormBinding(t *testing.T, method, path, badPath, body, badBody string) {
   839  	b := Form
   840  	assert.Equal(t, "form", b.Name())
   841  
   842  	obj := FooBarStruct{}
   843  	req := requestWithBody(method, path, body)
   844  	if method == "POST" {
   845  		req.Header.Add("Content-Type", MIMEPOSTForm)
   846  	}
   847  	err := b.Bind(req, &obj)
   848  	assert.NoError(t, err)
   849  	assert.Equal(t, "bar", obj.Foo)
   850  	assert.Equal(t, "foo", obj.Bar)
   851  
   852  	obj = FooBarStruct{}
   853  	req = requestWithBody(method, badPath, badBody)
   854  	err = JSON.Bind(req, &obj)
   855  	assert.Error(t, err)
   856  }
   857  
   858  func testFormBindingDefaultValue(t *testing.T, method, path, badPath, body, badBody string) {
   859  	b := Form
   860  	assert.Equal(t, "form", b.Name())
   861  
   862  	obj := FooDefaultBarStruct{}
   863  	req := requestWithBody(method, path, body)
   864  	if method == "POST" {
   865  		req.Header.Add("Content-Type", MIMEPOSTForm)
   866  	}
   867  	err := b.Bind(req, &obj)
   868  	assert.NoError(t, err)
   869  	assert.Equal(t, "bar", obj.Foo)
   870  	assert.Equal(t, "hello", obj.Bar)
   871  
   872  	obj = FooDefaultBarStruct{}
   873  	req = requestWithBody(method, badPath, badBody)
   874  	err = JSON.Bind(req, &obj)
   875  	assert.Error(t, err)
   876  }
   877  
   878  func TestFormBindingFail(t *testing.T) {
   879  	b := Form
   880  	assert.Equal(t, "form", b.Name())
   881  
   882  	obj := FooBarStruct{}
   883  	req, _ := http.NewRequest("POST", "/", nil)
   884  	err := b.Bind(req, &obj)
   885  	assert.Error(t, err)
   886  }
   887  
   888  func TestFormBindingMultipartFail(t *testing.T) {
   889  	obj := FooBarStruct{}
   890  	req, err := http.NewRequest("POST", "/", strings.NewReader("foo=bar"))
   891  	assert.NoError(t, err)
   892  	req.Header.Set("Content-Type", MIMEMultipartPOSTForm+";boundary=testboundary")
   893  	_, err = req.MultipartReader()
   894  	assert.NoError(t, err)
   895  	err = Form.Bind(req, &obj)
   896  	assert.Error(t, err)
   897  }
   898  
   899  func TestFormPostBindingFail(t *testing.T) {
   900  	b := FormPost
   901  	assert.Equal(t, "form-urlencoded", b.Name())
   902  
   903  	obj := FooBarStruct{}
   904  	req, _ := http.NewRequest("POST", "/", nil)
   905  	err := b.Bind(req, &obj)
   906  	assert.Error(t, err)
   907  }
   908  
   909  func TestFormMultipartBindingFail(t *testing.T) {
   910  	b := FormMultipart
   911  	assert.Equal(t, "multipart/form-data", b.Name())
   912  
   913  	obj := FooBarStruct{}
   914  	req, _ := http.NewRequest("POST", "/", nil)
   915  	err := b.Bind(req, &obj)
   916  	assert.Error(t, err)
   917  }
   918  
   919  func testFormBindingForTime(t *testing.T, method, path, badPath, body, badBody string) {
   920  	b := Form
   921  	assert.Equal(t, "form", b.Name())
   922  
   923  	obj := FooBarStructForTimeType{}
   924  	req := requestWithBody(method, path, body)
   925  	if method == "POST" {
   926  		req.Header.Add("Content-Type", MIMEPOSTForm)
   927  	}
   928  	err := b.Bind(req, &obj)
   929  
   930  	assert.NoError(t, err)
   931  	assert.Equal(t, int64(1510675200), obj.TimeFoo.Unix())
   932  	assert.Equal(t, "Asia/Chongqing", obj.TimeFoo.Location().String())
   933  	assert.Equal(t, int64(-62135596800), obj.TimeBar.Unix())
   934  	assert.Equal(t, "UTC", obj.TimeBar.Location().String())
   935  	assert.Equal(t, int64(1562400033000000123), obj.CreateTime.UnixNano())
   936  	assert.Equal(t, int64(1562400033), obj.UnixTime.Unix())
   937  
   938  	obj = FooBarStructForTimeType{}
   939  	req = requestWithBody(method, badPath, badBody)
   940  	err = JSON.Bind(req, &obj)
   941  	assert.Error(t, err)
   942  }
   943  
   944  func testFormBindingForTimeNotUnixFormat(t *testing.T, method, path, badPath, body, badBody string) {
   945  	b := Form
   946  	assert.Equal(t, "form", b.Name())
   947  
   948  	obj := FooStructForTimeTypeNotUnixFormat{}
   949  	req := requestWithBody(method, path, body)
   950  	if method == "POST" {
   951  		req.Header.Add("Content-Type", MIMEPOSTForm)
   952  	}
   953  	err := b.Bind(req, &obj)
   954  	assert.Error(t, err)
   955  
   956  	obj = FooStructForTimeTypeNotUnixFormat{}
   957  	req = requestWithBody(method, badPath, badBody)
   958  	err = JSON.Bind(req, &obj)
   959  	assert.Error(t, err)
   960  }
   961  
   962  func testFormBindingForTimeNotFormat(t *testing.T, method, path, badPath, body, badBody string) {
   963  	b := Form
   964  	assert.Equal(t, "form", b.Name())
   965  
   966  	obj := FooStructForTimeTypeNotFormat{}
   967  	req := requestWithBody(method, path, body)
   968  	if method == "POST" {
   969  		req.Header.Add("Content-Type", MIMEPOSTForm)
   970  	}
   971  	err := b.Bind(req, &obj)
   972  	assert.Error(t, err)
   973  
   974  	obj = FooStructForTimeTypeNotFormat{}
   975  	req = requestWithBody(method, badPath, badBody)
   976  	err = JSON.Bind(req, &obj)
   977  	assert.Error(t, err)
   978  }
   979  
   980  func testFormBindingForTimeFailFormat(t *testing.T, method, path, badPath, body, badBody string) {
   981  	b := Form
   982  	assert.Equal(t, "form", b.Name())
   983  
   984  	obj := FooStructForTimeTypeFailFormat{}
   985  	req := requestWithBody(method, path, body)
   986  	if method == "POST" {
   987  		req.Header.Add("Content-Type", MIMEPOSTForm)
   988  	}
   989  	err := b.Bind(req, &obj)
   990  	assert.Error(t, err)
   991  
   992  	obj = FooStructForTimeTypeFailFormat{}
   993  	req = requestWithBody(method, badPath, badBody)
   994  	err = JSON.Bind(req, &obj)
   995  	assert.Error(t, err)
   996  }
   997  
   998  func testFormBindingForTimeFailLocation(t *testing.T, method, path, badPath, body, badBody string) {
   999  	b := Form
  1000  	assert.Equal(t, "form", b.Name())
  1001  
  1002  	obj := FooStructForTimeTypeFailLocation{}
  1003  	req := requestWithBody(method, path, body)
  1004  	if method == "POST" {
  1005  		req.Header.Add("Content-Type", MIMEPOSTForm)
  1006  	}
  1007  	err := b.Bind(req, &obj)
  1008  	assert.Error(t, err)
  1009  
  1010  	obj = FooStructForTimeTypeFailLocation{}
  1011  	req = requestWithBody(method, badPath, badBody)
  1012  	err = JSON.Bind(req, &obj)
  1013  	assert.Error(t, err)
  1014  }
  1015  
  1016  func testFormBindingIgnoreField(t *testing.T, method, path, badPath, body, badBody string) {
  1017  	b := Form
  1018  	assert.Equal(t, "form", b.Name())
  1019  
  1020  	obj := FooStructForIgnoreFormTag{}
  1021  	req := requestWithBody(method, path, body)
  1022  	if method == "POST" {
  1023  		req.Header.Add("Content-Type", MIMEPOSTForm)
  1024  	}
  1025  	err := b.Bind(req, &obj)
  1026  	assert.NoError(t, err)
  1027  
  1028  	assert.Nil(t, obj.Foo)
  1029  }
  1030  
  1031  func testFormBindingInvalidName(t *testing.T, method, path, badPath, body, badBody string) {
  1032  	b := Form
  1033  	assert.Equal(t, "form", b.Name())
  1034  
  1035  	obj := InvalidNameType{}
  1036  	req := requestWithBody(method, path, body)
  1037  	if method == "POST" {
  1038  		req.Header.Add("Content-Type", MIMEPOSTForm)
  1039  	}
  1040  	err := b.Bind(req, &obj)
  1041  	assert.NoError(t, err)
  1042  	assert.Equal(t, "", obj.TestName)
  1043  
  1044  	obj = InvalidNameType{}
  1045  	req = requestWithBody(method, badPath, badBody)
  1046  	err = JSON.Bind(req, &obj)
  1047  	assert.Error(t, err)
  1048  }
  1049  
  1050  func testFormBindingInvalidName2(t *testing.T, method, path, badPath, body, badBody string) {
  1051  	b := Form
  1052  	assert.Equal(t, "form", b.Name())
  1053  
  1054  	obj := InvalidNameMapType{}
  1055  	req := requestWithBody(method, path, body)
  1056  	if method == "POST" {
  1057  		req.Header.Add("Content-Type", MIMEPOSTForm)
  1058  	}
  1059  	err := b.Bind(req, &obj)
  1060  	assert.Error(t, err)
  1061  
  1062  	obj = InvalidNameMapType{}
  1063  	req = requestWithBody(method, badPath, badBody)
  1064  	err = JSON.Bind(req, &obj)
  1065  	assert.Error(t, err)
  1066  }
  1067  
  1068  func testFormBindingForType(t *testing.T, method, path, badPath, body, badBody string, typ string) {
  1069  	b := Form
  1070  	assert.Equal(t, "form", b.Name())
  1071  
  1072  	req := requestWithBody(method, path, body)
  1073  	if method == "POST" {
  1074  		req.Header.Add("Content-Type", MIMEPOSTForm)
  1075  	}
  1076  	switch typ {
  1077  	case "Slice":
  1078  		obj := FooStructForSliceType{}
  1079  		err := b.Bind(req, &obj)
  1080  		assert.NoError(t, err)
  1081  		assert.Equal(t, []int{1, 2}, obj.SliceFoo)
  1082  
  1083  		obj = FooStructForSliceType{}
  1084  		req = requestWithBody(method, badPath, badBody)
  1085  		err = JSON.Bind(req, &obj)
  1086  		assert.Error(t, err)
  1087  	case "Struct":
  1088  		obj := FooStructForStructType{}
  1089  		err := b.Bind(req, &obj)
  1090  		assert.NoError(t, err)
  1091  		assert.Equal(t,
  1092  			struct {
  1093  				Idx int "form:\"idx\""
  1094  			}(struct {
  1095  				Idx int "form:\"idx\""
  1096  			}{Idx: 123}),
  1097  			obj.StructFoo)
  1098  	case "StructPointer":
  1099  		obj := FooStructForStructPointerType{}
  1100  		err := b.Bind(req, &obj)
  1101  		assert.NoError(t, err)
  1102  		assert.Equal(t,
  1103  			struct {
  1104  				Name string "form:\"name\""
  1105  			}(struct {
  1106  				Name string "form:\"name\""
  1107  			}{Name: "thinkerou"}),
  1108  			*obj.StructPointerFoo)
  1109  	case "Map":
  1110  		obj := FooStructForMapType{}
  1111  		err := b.Bind(req, &obj)
  1112  		assert.NoError(t, err)
  1113  		assert.Equal(t, float64(123), obj.MapFoo["bar"].(float64))
  1114  	case "SliceMap":
  1115  		obj := FooStructForSliceMapType{}
  1116  		err := b.Bind(req, &obj)
  1117  		assert.Error(t, err)
  1118  	case "Ptr":
  1119  		obj := FooStructForStringPtrType{}
  1120  		err := b.Bind(req, &obj)
  1121  		assert.NoError(t, err)
  1122  		assert.Nil(t, obj.PtrFoo)
  1123  		assert.Equal(t, "test", *obj.PtrBar)
  1124  
  1125  		obj = FooStructForStringPtrType{}
  1126  		obj.PtrBar = new(string)
  1127  		err = b.Bind(req, &obj)
  1128  		assert.NoError(t, err)
  1129  		assert.Equal(t, "test", *obj.PtrBar)
  1130  
  1131  		objErr := FooStructForMapPtrType{}
  1132  		err = b.Bind(req, &objErr)
  1133  		assert.Error(t, err)
  1134  
  1135  		obj = FooStructForStringPtrType{}
  1136  		req = requestWithBody(method, badPath, badBody)
  1137  		err = b.Bind(req, &obj)
  1138  		assert.Error(t, err)
  1139  	}
  1140  }
  1141  
  1142  func testQueryBinding(t *testing.T, method, path, badPath, body, badBody string) {
  1143  	b := Query
  1144  	assert.Equal(t, "query", b.Name())
  1145  
  1146  	obj := FooBarStruct{}
  1147  	req := requestWithBody(method, path, body)
  1148  	if method == "POST" {
  1149  		req.Header.Add("Content-Type", MIMEPOSTForm)
  1150  	}
  1151  	err := b.Bind(req, &obj)
  1152  	assert.NoError(t, err)
  1153  	assert.Equal(t, "bar", obj.Foo)
  1154  	assert.Equal(t, "foo", obj.Bar)
  1155  }
  1156  
  1157  func testQueryBindingFail(t *testing.T, method, path, badPath, body, badBody string) {
  1158  	b := Query
  1159  	assert.Equal(t, "query", b.Name())
  1160  
  1161  	obj := FooStructForMapType{}
  1162  	req := requestWithBody(method, path, body)
  1163  	if method == "POST" {
  1164  		req.Header.Add("Content-Type", MIMEPOSTForm)
  1165  	}
  1166  	err := b.Bind(req, &obj)
  1167  	assert.Error(t, err)
  1168  }
  1169  
  1170  func testQueryBindingBoolFail(t *testing.T, method, path, badPath, body, badBody string) {
  1171  	b := Query
  1172  	assert.Equal(t, "query", b.Name())
  1173  
  1174  	obj := FooStructForBoolType{}
  1175  	req := requestWithBody(method, path, body)
  1176  	if method == "POST" {
  1177  		req.Header.Add("Content-Type", MIMEPOSTForm)
  1178  	}
  1179  	err := b.Bind(req, &obj)
  1180  	assert.Error(t, err)
  1181  }
  1182  
  1183  func testBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
  1184  	assert.Equal(t, name, b.Name())
  1185  
  1186  	obj := FooStruct{}
  1187  	req := requestWithBody("POST", path, body)
  1188  	err := b.Bind(req, &obj)
  1189  	assert.NoError(t, err)
  1190  	assert.Equal(t, "bar", obj.Foo)
  1191  
  1192  	obj = FooStruct{}
  1193  	req = requestWithBody("POST", badPath, badBody)
  1194  	err = JSON.Bind(req, &obj)
  1195  	assert.Error(t, err)
  1196  }
  1197  
  1198  func testBodyBindingSlice(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
  1199  	assert.Equal(t, name, b.Name())
  1200  
  1201  	var obj1 []FooStruct
  1202  	req := requestWithBody("POST", path, body)
  1203  	err := b.Bind(req, &obj1)
  1204  	assert.NoError(t, err)
  1205  
  1206  	var obj2 []FooStruct
  1207  	req = requestWithBody("POST", badPath, badBody)
  1208  	err = JSON.Bind(req, &obj2)
  1209  	assert.Error(t, err)
  1210  }
  1211  
  1212  func testBodyBindingStringMap(t *testing.T, b Binding, path, badPath, body, badBody string) {
  1213  	obj := make(map[string]string)
  1214  	req := requestWithBody("POST", path, body)
  1215  	if b.Name() == "form" {
  1216  		req.Header.Add("Content-Type", MIMEPOSTForm)
  1217  	}
  1218  	err := b.Bind(req, &obj)
  1219  	assert.NoError(t, err)
  1220  	assert.NotNil(t, obj)
  1221  	assert.Len(t, obj, 2)
  1222  	assert.Equal(t, "bar", obj["foo"])
  1223  	assert.Equal(t, "world", obj["hello"])
  1224  
  1225  	if badPath != "" && badBody != "" {
  1226  		obj = make(map[string]string)
  1227  		req = requestWithBody("POST", badPath, badBody)
  1228  		err = b.Bind(req, &obj)
  1229  		assert.Error(t, err)
  1230  	}
  1231  
  1232  	objInt := make(map[string]int)
  1233  	req = requestWithBody("POST", path, body)
  1234  	err = b.Bind(req, &objInt)
  1235  	assert.Error(t, err)
  1236  }
  1237  
  1238  func testBodyBindingUseNumber(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
  1239  	assert.Equal(t, name, b.Name())
  1240  
  1241  	obj := FooStructUseNumber{}
  1242  	req := requestWithBody("POST", path, body)
  1243  	EnableDecoderUseNumber = true
  1244  	err := b.Bind(req, &obj)
  1245  	assert.NoError(t, err)
  1246  	// we hope it is int64(123)
  1247  	v, e := obj.Foo.(json.Number).Int64()
  1248  	assert.NoError(t, e)
  1249  	assert.Equal(t, int64(123), v)
  1250  
  1251  	obj = FooStructUseNumber{}
  1252  	req = requestWithBody("POST", badPath, badBody)
  1253  	err = JSON.Bind(req, &obj)
  1254  	assert.Error(t, err)
  1255  }
  1256  
  1257  func testBodyBindingUseNumber2(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
  1258  	assert.Equal(t, name, b.Name())
  1259  
  1260  	obj := FooStructUseNumber{}
  1261  	req := requestWithBody("POST", path, body)
  1262  	EnableDecoderUseNumber = false
  1263  	err := b.Bind(req, &obj)
  1264  	assert.NoError(t, err)
  1265  	// it will return float64(123) if not use EnableDecoderUseNumber
  1266  	// maybe it is not hoped
  1267  	assert.Equal(t, float64(123), obj.Foo)
  1268  
  1269  	obj = FooStructUseNumber{}
  1270  	req = requestWithBody("POST", badPath, badBody)
  1271  	err = JSON.Bind(req, &obj)
  1272  	assert.Error(t, err)
  1273  }
  1274  
  1275  func testBodyBindingDisallowUnknownFields(t *testing.T, b Binding, path, badPath, body, badBody string) {
  1276  	EnableDecoderDisallowUnknownFields = true
  1277  	defer func() {
  1278  		EnableDecoderDisallowUnknownFields = false
  1279  	}()
  1280  
  1281  	obj := FooStructDisallowUnknownFields{}
  1282  	req := requestWithBody("POST", path, body)
  1283  	err := b.Bind(req, &obj)
  1284  	assert.NoError(t, err)
  1285  	assert.Equal(t, "bar", obj.Foo)
  1286  
  1287  	obj = FooStructDisallowUnknownFields{}
  1288  	req = requestWithBody("POST", badPath, badBody)
  1289  	err = JSON.Bind(req, &obj)
  1290  	assert.Error(t, err)
  1291  	assert.Contains(t, err.Error(), "what")
  1292  }
  1293  
  1294  func testBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
  1295  	assert.Equal(t, name, b.Name())
  1296  
  1297  	obj := FooStruct{}
  1298  	req := requestWithBody("POST", path, body)
  1299  	err := b.Bind(req, &obj)
  1300  	assert.Error(t, err)
  1301  	assert.Equal(t, "", obj.Foo)
  1302  
  1303  	obj = FooStruct{}
  1304  	req = requestWithBody("POST", badPath, badBody)
  1305  	err = JSON.Bind(req, &obj)
  1306  	assert.Error(t, err)
  1307  }
  1308  
  1309  func testProtoBodyBinding(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
  1310  	assert.Equal(t, name, b.Name())
  1311  
  1312  	obj := protoexample.Test{}
  1313  	req := requestWithBody("POST", path, body)
  1314  	req.Header.Add("Content-Type", MIMEPROTOBUF)
  1315  	err := b.Bind(req, &obj)
  1316  	assert.NoError(t, err)
  1317  	assert.Equal(t, "yes", *obj.Label)
  1318  
  1319  	obj = protoexample.Test{}
  1320  	req = requestWithBody("POST", badPath, badBody)
  1321  	req.Header.Add("Content-Type", MIMEPROTOBUF)
  1322  	err = ProtoBuf.Bind(req, &obj)
  1323  	assert.Error(t, err)
  1324  }
  1325  
  1326  type hook struct{}
  1327  
  1328  func (h hook) Read([]byte) (int, error) {
  1329  	return 0, errors.New("error")
  1330  }
  1331  
  1332  func testProtoBodyBindingFail(t *testing.T, b Binding, name, path, badPath, body, badBody string) {
  1333  	assert.Equal(t, name, b.Name())
  1334  
  1335  	obj := protoexample.Test{}
  1336  	req := requestWithBody("POST", path, body)
  1337  
  1338  	req.Body = ioutil.NopCloser(&hook{})
  1339  	req.Header.Add("Content-Type", MIMEPROTOBUF)
  1340  	err := b.Bind(req, &obj)
  1341  	assert.Error(t, err)
  1342  
  1343  	obj = protoexample.Test{}
  1344  	req = requestWithBody("POST", badPath, badBody)
  1345  	req.Header.Add("Content-Type", MIMEPROTOBUF)
  1346  	err = ProtoBuf.Bind(req, &obj)
  1347  	assert.Error(t, err)
  1348  }
  1349  
  1350  func requestWithBody(method, path, body string) (req *http.Request) {
  1351  	req, _ = http.NewRequest(method, path, bytes.NewBufferString(body))
  1352  	return
  1353  }