...

Source file src/github.com/gin-gonic/gin/binding/binding_test.go

Documentation: github.com/gin-gonic/gin/binding

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

View as plain text