github.com/cloudwego/hertz@v0.9.3/pkg/app/server/binding/binder_test.go (about)

     1  /*
     2   * Copyright 2023 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   * MIT License
    16   *
    17   * Copyright (c) 2019-present Fenny and Contributors
    18   *
    19   * Permission is hereby granted, free of charge, to any person obtaining a copy
    20   * of this software and associated documentation files (the "Software"), to deal
    21   * in the Software without restriction, including without limitation the rights
    22   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    23   * copies of the Software, and to permit persons to whom the Software is
    24   * furnished to do so, subject to the following conditions:
    25   *
    26   * The above copyright notice and this permission notice shall be included in all
    27   * copies or substantial portions of the Software.
    28   *
    29   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    30   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    31   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    32   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    33   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    34   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    35   * SOFTWARE.
    36   *
    37   * This file may have been modified by CloudWeGo authors. All CloudWeGo
    38   * Modifications are Copyright 2023 CloudWeGo Authors
    39   */
    40  
    41  package binding
    42  
    43  import (
    44  	"encoding/json"
    45  	"fmt"
    46  	"mime/multipart"
    47  	"net/url"
    48  	"reflect"
    49  	"testing"
    50  	"time"
    51  
    52  	"github.com/cloudwego/hertz/pkg/app/server/binding/testdata"
    53  	"github.com/cloudwego/hertz/pkg/common/test/assert"
    54  	"github.com/cloudwego/hertz/pkg/protocol"
    55  	"github.com/cloudwego/hertz/pkg/protocol/consts"
    56  	req2 "github.com/cloudwego/hertz/pkg/protocol/http1/req"
    57  	"github.com/cloudwego/hertz/pkg/route/param"
    58  	"google.golang.org/protobuf/proto"
    59  )
    60  
    61  type mockRequest struct {
    62  	Req *protocol.Request
    63  }
    64  
    65  func newMockRequest() *mockRequest {
    66  	return &mockRequest{
    67  		Req: &protocol.Request{},
    68  	}
    69  }
    70  
    71  func (m *mockRequest) SetRequestURI(uri string) *mockRequest {
    72  	m.Req.SetRequestURI(uri)
    73  	return m
    74  }
    75  
    76  func (m *mockRequest) SetFile(param, fileName string) *mockRequest {
    77  	m.Req.SetFile(param, fileName)
    78  	return m
    79  }
    80  
    81  func (m *mockRequest) SetHeader(key, value string) *mockRequest {
    82  	m.Req.Header.Set(key, value)
    83  	return m
    84  }
    85  
    86  func (m *mockRequest) SetHeaders(key, value string) *mockRequest {
    87  	m.Req.Header.Set(key, value)
    88  	return m
    89  }
    90  
    91  func (m *mockRequest) SetPostArg(key, value string) *mockRequest {
    92  	m.Req.PostArgs().Add(key, value)
    93  	return m
    94  }
    95  
    96  func (m *mockRequest) SetUrlEncodeContentType() *mockRequest {
    97  	m.Req.Header.SetContentTypeBytes([]byte("application/x-www-form-urlencoded"))
    98  	return m
    99  }
   100  
   101  func (m *mockRequest) SetJSONContentType() *mockRequest {
   102  	m.Req.Header.SetContentTypeBytes([]byte(consts.MIMEApplicationJSON))
   103  	return m
   104  }
   105  
   106  func (m *mockRequest) SetProtobufContentType() *mockRequest {
   107  	m.Req.Header.SetContentTypeBytes([]byte(consts.MIMEPROTOBUF))
   108  	return m
   109  }
   110  
   111  func (m *mockRequest) SetBody(data []byte) *mockRequest {
   112  	m.Req.SetBody(data)
   113  	m.Req.Header.SetContentLength(len(data))
   114  	return m
   115  }
   116  
   117  func TestBind_BaseType(t *testing.T) {
   118  	type Req struct {
   119  		Version int    `path:"v"`
   120  		ID      int    `query:"id"`
   121  		Header  string `header:"H"`
   122  		Form    string `form:"f"`
   123  	}
   124  
   125  	req := newMockRequest().
   126  		SetRequestURI("http://foobar.com?id=12").
   127  		SetHeaders("H", "header").
   128  		SetPostArg("f", "form").
   129  		SetUrlEncodeContentType()
   130  	var params param.Params
   131  	params = append(params, param.Param{
   132  		Key:   "v",
   133  		Value: "1",
   134  	})
   135  
   136  	var result Req
   137  
   138  	err := DefaultBinder().Bind(req.Req, &result, params)
   139  	if err != nil {
   140  		t.Error(err)
   141  	}
   142  	assert.DeepEqual(t, 1, result.Version)
   143  	assert.DeepEqual(t, 12, result.ID)
   144  	assert.DeepEqual(t, "header", result.Header)
   145  	assert.DeepEqual(t, "form", result.Form)
   146  }
   147  
   148  func TestBind_SliceType(t *testing.T) {
   149  	type Req struct {
   150  		ID   *[]int    `query:"id"`
   151  		Str  [3]string `query:"str"`
   152  		Byte []byte    `query:"b"`
   153  	}
   154  	IDs := []int{11, 12, 13}
   155  	Strs := [3]string{"qwe", "asd", "zxc"}
   156  	Bytes := []byte("123")
   157  
   158  	req := newMockRequest().
   159  		SetRequestURI(fmt.Sprintf("http://foobar.com?id=%d&id=%d&id=%d&str=%s&str=%s&str=%s&b=%d&b=%d&b=%d", IDs[0], IDs[1], IDs[2], Strs[0], Strs[1], Strs[2], Bytes[0], Bytes[1], Bytes[2]))
   160  
   161  	var result Req
   162  
   163  	err := DefaultBinder().Bind(req.Req, &result, nil)
   164  	if err != nil {
   165  		t.Error(err)
   166  	}
   167  	assert.DeepEqual(t, 3, len(*result.ID))
   168  	for idx, val := range IDs {
   169  		assert.DeepEqual(t, val, (*result.ID)[idx])
   170  	}
   171  	assert.DeepEqual(t, 3, len(result.Str))
   172  	for idx, val := range Strs {
   173  		assert.DeepEqual(t, val, result.Str[idx])
   174  	}
   175  	assert.DeepEqual(t, 3, len(result.Byte))
   176  	for idx, val := range Bytes {
   177  		assert.DeepEqual(t, val, result.Byte[idx])
   178  	}
   179  }
   180  
   181  func TestBind_StructType(t *testing.T) {
   182  	type FFF struct {
   183  		F1 string `query:"F1"`
   184  	}
   185  
   186  	type TTT struct {
   187  		T1 string `query:"F1"`
   188  		T2 FFF
   189  	}
   190  
   191  	type Foo struct {
   192  		F1 string `query:"F1"`
   193  		F2 string `header:"f2"`
   194  		F3 TTT
   195  	}
   196  
   197  	type Bar struct {
   198  		B1 string `query:"B1"`
   199  		B2 Foo    `query:"B2"`
   200  	}
   201  
   202  	var result Bar
   203  
   204  	req := newMockRequest().SetRequestURI("http://foobar.com?F1=f1&B1=b1").SetHeader("f2", "f2")
   205  
   206  	err := DefaultBinder().Bind(req.Req, &result, nil)
   207  	if err != nil {
   208  		t.Error(err)
   209  	}
   210  
   211  	assert.DeepEqual(t, "b1", result.B1)
   212  	assert.DeepEqual(t, "f1", result.B2.F1)
   213  	assert.DeepEqual(t, "f2", result.B2.F2)
   214  	assert.DeepEqual(t, "f1", result.B2.F3.T1)
   215  	assert.DeepEqual(t, "f1", result.B2.F3.T2.F1)
   216  }
   217  
   218  func TestBind_PointerType(t *testing.T) {
   219  	type TT struct {
   220  		T1 string `query:"F1"`
   221  	}
   222  
   223  	type Foo struct {
   224  		F1 *TT                       `query:"F1"`
   225  		F2 *******************string `query:"F1"`
   226  	}
   227  
   228  	type Bar struct {
   229  		B1 ***string `query:"B1"`
   230  		B2 ****Foo   `query:"B2"`
   231  		B3 []*string `query:"B3"`
   232  		B4 [2]*int   `query:"B4"`
   233  	}
   234  
   235  	result := Bar{}
   236  
   237  	F1 := "f1"
   238  	B1 := "b1"
   239  	B2 := "b2"
   240  	B3s := []string{"b31", "b32"}
   241  	B4s := [2]int{0, 1}
   242  
   243  	req := newMockRequest().SetRequestURI(fmt.Sprintf("http://foobar.com?F1=%s&B1=%s&B2=%s&B3=%s&B3=%s&B4=%d&B4=%d", F1, B1, B2, B3s[0], B3s[1], B4s[0], B4s[1])).
   244  		SetHeader("f2", "f2")
   245  
   246  	err := DefaultBinder().Bind(req.Req, &result, nil)
   247  	if err != nil {
   248  		t.Error(err)
   249  	}
   250  	assert.DeepEqual(t, B1, ***result.B1)
   251  	assert.DeepEqual(t, F1, (*(****result.B2).F1).T1)
   252  	assert.DeepEqual(t, F1, *******************(****result.B2).F2)
   253  	assert.DeepEqual(t, len(B3s), len(result.B3))
   254  	for idx, val := range B3s {
   255  		assert.DeepEqual(t, val, *result.B3[idx])
   256  	}
   257  	assert.DeepEqual(t, len(B4s), len(result.B4))
   258  	for idx, val := range B4s {
   259  		assert.DeepEqual(t, val, *result.B4[idx])
   260  	}
   261  }
   262  
   263  func TestBind_NestedStruct(t *testing.T) {
   264  	type Foo struct {
   265  		F1 string `query:"F1"`
   266  	}
   267  
   268  	type Bar struct {
   269  		Foo
   270  		Nested struct {
   271  			N1 string `query:"F1"`
   272  		}
   273  	}
   274  
   275  	result := Bar{}
   276  
   277  	req := newMockRequest().SetRequestURI("http://foobar.com?F1=qwe")
   278  	err := DefaultBinder().Bind(req.Req, &result, nil)
   279  	if err != nil {
   280  		t.Error(err)
   281  	}
   282  	assert.DeepEqual(t, "qwe", result.Foo.F1)
   283  	assert.DeepEqual(t, "qwe", result.Nested.N1)
   284  }
   285  
   286  func TestBind_SliceStruct(t *testing.T) {
   287  	type Foo struct {
   288  		F1 string `json:"f1"`
   289  	}
   290  
   291  	type Bar struct {
   292  		B1 []Foo `query:"F1"`
   293  	}
   294  
   295  	result := Bar{}
   296  	B1s := []string{"1", "2", "3"}
   297  
   298  	req := newMockRequest().SetRequestURI(fmt.Sprintf("http://foobar.com?F1={\"f1\":\"%s\"}&F1={\"f1\":\"%s\"}&F1={\"f1\":\"%s\"}", B1s[0], B1s[1], B1s[2]))
   299  	err := DefaultBinder().Bind(req.Req, &result, nil)
   300  	if err != nil {
   301  		t.Error(err)
   302  	}
   303  	assert.DeepEqual(t, len(result.B1), len(B1s))
   304  	for idx, val := range B1s {
   305  		assert.DeepEqual(t, B1s[idx], val)
   306  	}
   307  }
   308  
   309  func TestBind_MapType(t *testing.T) {
   310  	var result map[string]string
   311  	req := newMockRequest().
   312  		SetJSONContentType().
   313  		SetBody([]byte(`{"j1":"j1", "j2":"j2"}`))
   314  	err := DefaultBinder().Bind(req.Req, &result, nil)
   315  	if err != nil {
   316  		t.Fatal(err)
   317  	}
   318  	assert.DeepEqual(t, 2, len(result))
   319  	assert.DeepEqual(t, "j1", result["j1"])
   320  	assert.DeepEqual(t, "j2", result["j2"])
   321  }
   322  
   323  func TestBind_MapFieldType(t *testing.T) {
   324  	type Foo struct {
   325  		F1 ***map[string]string `query:"f1" json:"f1"`
   326  	}
   327  
   328  	req := newMockRequest().
   329  		SetRequestURI("http://foobar.com?f1={\"f1\":\"f1\"}").
   330  		SetJSONContentType().
   331  		SetBody([]byte(`{"j1":"j1", "j2":"j2"}`))
   332  	result := Foo{}
   333  	err := DefaultBinder().Bind(req.Req, &result, nil)
   334  	if err != nil {
   335  		t.Fatal(err)
   336  	}
   337  	assert.DeepEqual(t, 1, len(***result.F1))
   338  	assert.DeepEqual(t, "f1", (***result.F1)["f1"])
   339  
   340  	type Foo2 struct {
   341  		F1 map[string]string `query:"f1" json:"f1"`
   342  	}
   343  	result2 := Foo2{}
   344  	err = DefaultBinder().Bind(req.Req, &result2, nil)
   345  	if err != nil {
   346  		t.Fatal(err)
   347  	}
   348  	assert.DeepEqual(t, 1, len(result2.F1))
   349  	assert.DeepEqual(t, "f1", result2.F1["f1"])
   350  	req = newMockRequest().
   351  		SetRequestURI("http://foobar.com?f1={\"f1\":\"f1\"")
   352  	result2 = Foo2{}
   353  	err = DefaultBinder().Bind(req.Req, &result2, nil)
   354  	if err == nil {
   355  		t.Error(err)
   356  	}
   357  }
   358  
   359  func TestBind_UnexportedField(t *testing.T) {
   360  	var s struct {
   361  		A int `query:"a"`
   362  		b int `query:"b"`
   363  	}
   364  	req := newMockRequest().
   365  		SetRequestURI("http://foobar.com?a=1&b=2")
   366  	err := DefaultBinder().Bind(req.Req, &s, nil)
   367  	if err != nil {
   368  		t.Fatal(err)
   369  	}
   370  	assert.DeepEqual(t, 1, s.A)
   371  	assert.DeepEqual(t, 0, s.b)
   372  }
   373  
   374  func TestBind_NoTagField(t *testing.T) {
   375  	var s struct {
   376  		A string
   377  		B string
   378  		C string
   379  	}
   380  	req := newMockRequest().
   381  		SetRequestURI("http://foobar.com?B=b1&C=c1").
   382  		SetHeader("A", "a2")
   383  
   384  	var params param.Params
   385  	params = append(params, param.Param{
   386  		Key:   "B",
   387  		Value: "b2",
   388  	})
   389  
   390  	err := DefaultBinder().Bind(req.Req, &s, params)
   391  	if err != nil {
   392  		t.Fatal(err)
   393  	}
   394  	assert.DeepEqual(t, "a2", s.A)
   395  	assert.DeepEqual(t, "b2", s.B)
   396  	assert.DeepEqual(t, "c1", s.C)
   397  }
   398  
   399  func TestBind_ZeroValueBind(t *testing.T) {
   400  	var s struct {
   401  		A int     `query:"a"`
   402  		B float64 `query:"b"`
   403  	}
   404  	req := newMockRequest().
   405  		SetRequestURI("http://foobar.com?a=&b")
   406  
   407  	bindConfig := &BindConfig{}
   408  	bindConfig.LooseZeroMode = true
   409  	binder := NewDefaultBinder(bindConfig)
   410  	err := binder.Bind(req.Req, &s, nil)
   411  	if err != nil {
   412  		t.Fatal(err)
   413  	}
   414  	assert.DeepEqual(t, 0, s.A)
   415  	assert.DeepEqual(t, float64(0), s.B)
   416  }
   417  
   418  func TestBind_DefaultValueBind(t *testing.T) {
   419  	var s struct {
   420  		A int       `default:"15"`
   421  		B float64   `query:"b" default:"17"`
   422  		C []int     `default:"[15]"`
   423  		D []string  `default:"['qwe','asd']"`
   424  		F [2]string `default:"['qwe','asd','zxc']"`
   425  	}
   426  	req := newMockRequest().
   427  		SetRequestURI("http://foobar.com")
   428  
   429  	err := DefaultBinder().Bind(req.Req, &s, nil)
   430  	if err != nil {
   431  		t.Fatal(err)
   432  	}
   433  	assert.DeepEqual(t, 15, s.A)
   434  	assert.DeepEqual(t, float64(17), s.B)
   435  	assert.DeepEqual(t, 15, s.C[0])
   436  	assert.DeepEqual(t, 2, len(s.D))
   437  	assert.DeepEqual(t, "qwe", s.D[0])
   438  	assert.DeepEqual(t, "asd", s.D[1])
   439  	assert.DeepEqual(t, 2, len(s.F))
   440  	assert.DeepEqual(t, "qwe", s.F[0])
   441  	assert.DeepEqual(t, "asd", s.F[1])
   442  
   443  	var s2 struct {
   444  		F [2]string `default:"['qwe']"`
   445  	}
   446  	err = DefaultBinder().Bind(req.Req, &s2, nil)
   447  	if err != nil {
   448  		t.Fatal(err)
   449  	}
   450  	assert.DeepEqual(t, 2, len(s2.F))
   451  	assert.DeepEqual(t, "qwe", s2.F[0])
   452  	assert.DeepEqual(t, "", s2.F[1])
   453  
   454  	var d struct {
   455  		D [2]string `default:"qwe"`
   456  	}
   457  
   458  	err = DefaultBinder().Bind(req.Req, &d, nil)
   459  	if err == nil {
   460  		t.Fatal("expected err")
   461  	}
   462  }
   463  
   464  func TestBind_RequiredBind(t *testing.T) {
   465  	var s struct {
   466  		A int `query:"a,required"`
   467  	}
   468  	req := newMockRequest().
   469  		SetRequestURI("http://foobar.com")
   470  	err := DefaultBinder().Bind(req.Req, &s, nil)
   471  	assert.DeepEqual(t, "'a' field is a 'required' parameter, but the request does not have this parameter", err.Error())
   472  
   473  	req = newMockRequest().
   474  		SetRequestURI("http://foobar.com").
   475  		SetHeader("A", "1")
   476  	err = DefaultBinder().Bind(req.Req, &s, nil)
   477  	if err == nil {
   478  		t.Fatal("expected error")
   479  	}
   480  
   481  	var d struct {
   482  		A int `query:"a,required" header:"A"`
   483  	}
   484  	err = DefaultBinder().Bind(req.Req, &d, nil)
   485  	if err != nil {
   486  		t.Fatal(err)
   487  	}
   488  	assert.DeepEqual(t, 1, d.A)
   489  }
   490  
   491  func TestBind_TypedefType(t *testing.T) {
   492  	type Foo string
   493  	type Bar *int
   494  	type T struct {
   495  		T1 string `query:"a"`
   496  	}
   497  	type TT T
   498  
   499  	var s struct {
   500  		A  Foo `query:"a"`
   501  		B  Bar `query:"b"`
   502  		T1 TT
   503  	}
   504  	req := newMockRequest().
   505  		SetRequestURI("http://foobar.com?a=1&b=2")
   506  	err := DefaultBinder().Bind(req.Req, &s, nil)
   507  	if err != nil {
   508  		t.Fatal(err)
   509  	}
   510  	assert.DeepEqual(t, Foo("1"), s.A)
   511  	assert.DeepEqual(t, 2, *s.B)
   512  	assert.DeepEqual(t, "1", s.T1.T1)
   513  }
   514  
   515  type EnumType int64
   516  
   517  const (
   518  	EnumType_TWEET   EnumType = 0
   519  	EnumType_RETWEET EnumType = 2
   520  )
   521  
   522  func (p EnumType) String() string {
   523  	switch p {
   524  	case EnumType_TWEET:
   525  		return "TWEET"
   526  	case EnumType_RETWEET:
   527  		return "RETWEET"
   528  	}
   529  	return "<UNSET>"
   530  }
   531  
   532  func TestBind_EnumBind(t *testing.T) {
   533  	var s struct {
   534  		A EnumType `query:"a"`
   535  		B EnumType `query:"b"`
   536  	}
   537  	req := newMockRequest().
   538  		SetRequestURI("http://foobar.com?a=0&b=2")
   539  	err := DefaultBinder().Bind(req.Req, &s, nil)
   540  	if err != nil {
   541  		t.Fatal(err)
   542  	}
   543  }
   544  
   545  type CustomizedDecode struct {
   546  	A string
   547  }
   548  
   549  func TestBind_CustomizedTypeDecode(t *testing.T) {
   550  	type Foo struct {
   551  		F ***CustomizedDecode `query:"a"`
   552  	}
   553  
   554  	bindConfig := &BindConfig{}
   555  	err := bindConfig.RegTypeUnmarshal(reflect.TypeOf(CustomizedDecode{}), func(req *protocol.Request, params param.Params, text string) (reflect.Value, error) {
   556  		q1 := req.URI().QueryArgs().Peek("a")
   557  		if len(q1) == 0 {
   558  			return reflect.Value{}, fmt.Errorf("can be nil")
   559  		}
   560  		val := CustomizedDecode{
   561  			A: string(q1),
   562  		}
   563  		return reflect.ValueOf(val), nil
   564  	})
   565  	if err != nil {
   566  		t.Fatal(err)
   567  	}
   568  	binder := NewDefaultBinder(bindConfig)
   569  
   570  	req := newMockRequest().
   571  		SetRequestURI("http://foobar.com?a=1&b=2")
   572  	result := Foo{}
   573  	err = binder.Bind(req.Req, &result, nil)
   574  	if err != nil {
   575  		t.Fatal(err)
   576  	}
   577  	assert.DeepEqual(t, "1", (***result.F).A)
   578  
   579  	type Bar struct {
   580  		B *Foo
   581  	}
   582  
   583  	result2 := Bar{}
   584  	err = binder.Bind(req.Req, &result2, nil)
   585  	if err != nil {
   586  		t.Error(err)
   587  	}
   588  	assert.DeepEqual(t, "1", (***(*result2.B).F).A)
   589  }
   590  
   591  func TestBind_CustomizedTypeDecodeForPanic(t *testing.T) {
   592  	defer func() {
   593  		if r := recover(); r == nil {
   594  			t.Errorf("expect a panic, but get nil")
   595  		}
   596  	}()
   597  
   598  	bindConfig := &BindConfig{}
   599  	bindConfig.MustRegTypeUnmarshal(reflect.TypeOf(string("")), func(req *protocol.Request, params param.Params, text string) (reflect.Value, error) {
   600  		return reflect.Value{}, nil
   601  	})
   602  }
   603  
   604  func TestBind_JSON(t *testing.T) {
   605  	type Req struct {
   606  		J1 string    `json:"j1"`
   607  		J2 int       `json:"j2" query:"j2"` // 1. json unmarshal 2. query binding cover
   608  		J3 []byte    `json:"j3"`
   609  		J4 [2]string `json:"j4"`
   610  	}
   611  	J3s := []byte("12")
   612  	J4s := [2]string{"qwe", "asd"}
   613  
   614  	req := newMockRequest().
   615  		SetRequestURI("http://foobar.com?j2=13").
   616  		SetJSONContentType().
   617  		SetBody([]byte(fmt.Sprintf(`{"j1":"j1", "j2":12, "j3":[%d, %d], "j4":["%s", "%s"]}`, J3s[0], J3s[1], J4s[0], J4s[1])))
   618  	var result Req
   619  	err := DefaultBinder().Bind(req.Req, &result, nil)
   620  	if err != nil {
   621  		t.Error(err)
   622  	}
   623  	assert.DeepEqual(t, "j1", result.J1)
   624  	assert.DeepEqual(t, 13, result.J2)
   625  	for idx, val := range J3s {
   626  		assert.DeepEqual(t, val, result.J3[idx])
   627  	}
   628  	for idx, val := range J4s {
   629  		assert.DeepEqual(t, val, result.J4[idx])
   630  	}
   631  }
   632  
   633  func TestBind_ResetJSONUnmarshal(t *testing.T) {
   634  	bindConfig := &BindConfig{}
   635  	bindConfig.UseStdJSONUnmarshaler()
   636  	binder := NewDefaultBinder(bindConfig)
   637  	type Req struct {
   638  		J1 string    `json:"j1"`
   639  		J2 int       `json:"j2"`
   640  		J3 []byte    `json:"j3"`
   641  		J4 [2]string `json:"j4"`
   642  	}
   643  	J3s := []byte("12")
   644  	J4s := [2]string{"qwe", "asd"}
   645  
   646  	req := newMockRequest().
   647  		SetJSONContentType().
   648  		SetBody([]byte(fmt.Sprintf(`{"j1":"j1", "j2":12, "j3":[%d, %d], "j4":["%s", "%s"]}`, J3s[0], J3s[1], J4s[0], J4s[1])))
   649  	var result Req
   650  	err := binder.Bind(req.Req, &result, nil)
   651  	if err != nil {
   652  		t.Error(err)
   653  	}
   654  	assert.DeepEqual(t, "j1", result.J1)
   655  	assert.DeepEqual(t, 12, result.J2)
   656  	for idx, val := range J3s {
   657  		assert.DeepEqual(t, val, result.J3[idx])
   658  	}
   659  	for idx, val := range J4s {
   660  		assert.DeepEqual(t, val, result.J4[idx])
   661  	}
   662  }
   663  
   664  func TestBind_FileBind(t *testing.T) {
   665  	type Nest struct {
   666  		N multipart.FileHeader `file_name:"d"`
   667  	}
   668  
   669  	var s struct {
   670  		A *multipart.FileHeader `file_name:"a"`
   671  		B *multipart.FileHeader `form:"b"`
   672  		C multipart.FileHeader
   673  		D **Nest `file_name:"d"`
   674  	}
   675  	fileName := "binder_test.go"
   676  	req := newMockRequest().
   677  		SetRequestURI("http://foobar.com").
   678  		SetFile("a", fileName).
   679  		SetFile("b", fileName).
   680  		SetFile("C", fileName).
   681  		SetFile("d", fileName)
   682  	// to parse multipart files
   683  	req2 := req2.GetHTTP1Request(req.Req)
   684  	_ = req2.String()
   685  	err := DefaultBinder().Bind(req.Req, &s, nil)
   686  	if err != nil {
   687  		t.Fatal(err)
   688  	}
   689  	assert.DeepEqual(t, fileName, s.A.Filename)
   690  	assert.DeepEqual(t, fileName, s.B.Filename)
   691  	assert.DeepEqual(t, fileName, s.C.Filename)
   692  	assert.DeepEqual(t, fileName, (**s.D).N.Filename)
   693  }
   694  
   695  func TestBind_FileBindWithNoFile(t *testing.T) {
   696  	var s struct {
   697  		A *multipart.FileHeader `file_name:"a"`
   698  		B *multipart.FileHeader `form:"b"`
   699  		C *multipart.FileHeader
   700  	}
   701  	fileName := "binder_test.go"
   702  	req := newMockRequest().
   703  		SetRequestURI("http://foobar.com").
   704  		SetFile("a", fileName).
   705  		SetFile("b", fileName)
   706  	// to parse multipart files
   707  	req2 := req2.GetHTTP1Request(req.Req)
   708  	_ = req2.String()
   709  	err := DefaultBinder().Bind(req.Req, &s, nil)
   710  	if err != nil {
   711  		t.Fatalf("unexpected err: %v", err)
   712  	}
   713  	assert.DeepEqual(t, fileName, s.A.Filename)
   714  	assert.DeepEqual(t, fileName, s.B.Filename)
   715  	if s.C != nil {
   716  		t.Fatalf("expected a nil for s.C")
   717  	}
   718  }
   719  
   720  func TestBind_FileSliceBind(t *testing.T) {
   721  	type Nest struct {
   722  		N *[]*multipart.FileHeader `form:"b"`
   723  	}
   724  	var s struct {
   725  		A []multipart.FileHeader  `form:"a"`
   726  		B [3]multipart.FileHeader `form:"b"`
   727  		C []*multipart.FileHeader `form:"b"`
   728  		D Nest
   729  	}
   730  	fileName := "binder_test.go"
   731  	req := newMockRequest().
   732  		SetRequestURI("http://foobar.com").
   733  		SetFile("a", fileName).
   734  		SetFile("a", fileName).
   735  		SetFile("a", fileName).
   736  		SetFile("b", fileName).
   737  		SetFile("b", fileName).
   738  		SetFile("b", fileName)
   739  	// to parse multipart files
   740  	req2 := req2.GetHTTP1Request(req.Req)
   741  	_ = req2.String()
   742  	err := DefaultBinder().Bind(req.Req, &s, nil)
   743  	if err != nil {
   744  		t.Fatal(err)
   745  	}
   746  	assert.DeepEqual(t, 3, len(s.A))
   747  	for _, file := range s.A {
   748  		assert.DeepEqual(t, fileName, file.Filename)
   749  	}
   750  	assert.DeepEqual(t, 3, len(s.B))
   751  	for _, file := range s.B {
   752  		assert.DeepEqual(t, fileName, file.Filename)
   753  	}
   754  	assert.DeepEqual(t, 3, len(s.C))
   755  	for _, file := range s.C {
   756  		assert.DeepEqual(t, fileName, file.Filename)
   757  	}
   758  	assert.DeepEqual(t, 3, len(*s.D.N))
   759  	for _, file := range *s.D.N {
   760  		assert.DeepEqual(t, fileName, file.Filename)
   761  	}
   762  }
   763  
   764  func TestBind_AnonymousField(t *testing.T) {
   765  	type nest struct {
   766  		n1     string       `query:"n1"` // bind default value
   767  		N2     ***string    `query:"n2"` // bind n2 value
   768  		string `query:"n3"` // bind default value
   769  	}
   770  
   771  	var s struct {
   772  		s1  int          `query:"s1"` // bind default value
   773  		int `query:"s2"` // bind default value
   774  		nest
   775  	}
   776  	req := newMockRequest().
   777  		SetRequestURI("http://foobar.com?s1=1&s2=2&n1=1&n2=2&n3=3")
   778  	err := DefaultBinder().Bind(req.Req, &s, nil)
   779  	if err != nil {
   780  		t.Fatal(err)
   781  	}
   782  	assert.DeepEqual(t, 0, s.s1)
   783  	assert.DeepEqual(t, 0, s.int)
   784  	assert.DeepEqual(t, "", s.nest.n1)
   785  	assert.DeepEqual(t, "2", ***s.nest.N2)
   786  	assert.DeepEqual(t, "", s.nest.string)
   787  }
   788  
   789  func TestBind_IgnoreField(t *testing.T) {
   790  	type Req struct {
   791  		Version int    `path:"-"`
   792  		ID      int    `query:"-"`
   793  		Header  string `header:"-"`
   794  		Form    string `form:"-"`
   795  	}
   796  
   797  	req := newMockRequest().
   798  		SetRequestURI("http://foobar.com?ID=12").
   799  		SetHeaders("Header", "header").
   800  		SetPostArg("Form", "form").
   801  		SetUrlEncodeContentType()
   802  	var params param.Params
   803  	params = append(params, param.Param{
   804  		Key:   "Version",
   805  		Value: "1",
   806  	})
   807  
   808  	var result Req
   809  
   810  	err := DefaultBinder().Bind(req.Req, &result, params)
   811  	if err != nil {
   812  		t.Error(err)
   813  	}
   814  	assert.DeepEqual(t, 0, result.Version)
   815  	assert.DeepEqual(t, 0, result.ID)
   816  	assert.DeepEqual(t, "", result.Header)
   817  	assert.DeepEqual(t, "", result.Form)
   818  }
   819  
   820  func TestBind_DefaultTag(t *testing.T) {
   821  	type Req struct {
   822  		Version int
   823  		ID      int
   824  		Header  string
   825  		Form    string
   826  	}
   827  	type Req2 struct {
   828  		Version int
   829  		ID      int
   830  		Header  string
   831  		Form    string
   832  	}
   833  	req := newMockRequest().
   834  		SetRequestURI("http://foobar.com?ID=12").
   835  		SetHeaders("Header", "header").
   836  		SetPostArg("Form", "form").
   837  		SetUrlEncodeContentType()
   838  	var params param.Params
   839  	params = append(params, param.Param{
   840  		Key:   "Version",
   841  		Value: "1",
   842  	})
   843  	var result Req
   844  	err := DefaultBinder().Bind(req.Req, &result, params)
   845  	if err != nil {
   846  		t.Error(err)
   847  	}
   848  	assert.DeepEqual(t, 1, result.Version)
   849  	assert.DeepEqual(t, 12, result.ID)
   850  	assert.DeepEqual(t, "header", result.Header)
   851  	assert.DeepEqual(t, "form", result.Form)
   852  
   853  	bindConfig := &BindConfig{}
   854  	bindConfig.DisableDefaultTag = true
   855  	binder := NewDefaultBinder(bindConfig)
   856  	result2 := Req2{}
   857  	err = binder.Bind(req.Req, &result2, params)
   858  	if err != nil {
   859  		t.Error(err)
   860  	}
   861  	assert.DeepEqual(t, 0, result2.Version)
   862  	assert.DeepEqual(t, 0, result2.ID)
   863  	assert.DeepEqual(t, "", result2.Header)
   864  	assert.DeepEqual(t, "", result2.Form)
   865  }
   866  
   867  func TestBind_StructFieldResolve(t *testing.T) {
   868  	type Nested struct {
   869  		A int `query:"a" json:"a"`
   870  		B int `query:"b" json:"b"`
   871  	}
   872  	type Req struct {
   873  		N Nested `query:"n"`
   874  	}
   875  
   876  	req := newMockRequest().
   877  		SetRequestURI("http://foobar.com?n={\"a\":1,\"b\":2}").
   878  		SetHeaders("Header", "header").
   879  		SetPostArg("Form", "form").
   880  		SetUrlEncodeContentType()
   881  	var result Req
   882  	bindConfig := &BindConfig{}
   883  	bindConfig.DisableStructFieldResolve = false
   884  	binder := NewDefaultBinder(bindConfig)
   885  	err := binder.Bind(req.Req, &result, nil)
   886  	if err != nil {
   887  		t.Error(err)
   888  	}
   889  	assert.DeepEqual(t, 1, result.N.A)
   890  	assert.DeepEqual(t, 2, result.N.B)
   891  
   892  	req = newMockRequest().
   893  		SetRequestURI("http://foobar.com?n={\"a\":1,\"b\":2}&a=11&b=22").
   894  		SetHeaders("Header", "header").
   895  		SetPostArg("Form", "form").
   896  		SetUrlEncodeContentType()
   897  	err = DefaultBinder().Bind(req.Req, &result, nil)
   898  	if err != nil {
   899  		t.Error(err)
   900  	}
   901  	assert.DeepEqual(t, 11, result.N.A)
   902  	assert.DeepEqual(t, 22, result.N.B)
   903  }
   904  
   905  func TestBind_JSONRequiredField(t *testing.T) {
   906  	type Nested2 struct {
   907  		C int `json:"c,required"`
   908  		D int `json:"dd,required"`
   909  	}
   910  	type Nested struct {
   911  		A  int     `json:"a,required"`
   912  		B  int     `json:"b,required"`
   913  		N2 Nested2 `json:"n2"`
   914  	}
   915  	type Req struct {
   916  		N Nested `json:"n,required"`
   917  	}
   918  	bodyBytes := []byte(`{
   919      "n": {
   920          "a": 1,
   921          "b": 2,
   922          "n2": {
   923               "dd": 4
   924          }
   925      }
   926  }`)
   927  	req := newMockRequest().
   928  		SetRequestURI("http://foobar.com?j2=13").
   929  		SetJSONContentType().
   930  		SetBody(bodyBytes)
   931  	var result Req
   932  	err := DefaultBinder().Bind(req.Req, &result, nil)
   933  	if err == nil {
   934  		t.Errorf("expected an error, but get nil")
   935  	}
   936  	assert.DeepEqual(t, "'c' field is a 'required' parameter, but the request body does not have this parameter 'n.n2.c'", err.Error())
   937  	assert.DeepEqual(t, 1, result.N.A)
   938  	assert.DeepEqual(t, 2, result.N.B)
   939  	assert.DeepEqual(t, 0, result.N.N2.C)
   940  	assert.DeepEqual(t, 4, result.N.N2.D)
   941  
   942  	bodyBytes = []byte(`{
   943      "n": {
   944          "a": 1,
   945          "b": 2
   946      }
   947  }`)
   948  	req = newMockRequest().
   949  		SetRequestURI("http://foobar.com?j2=13").
   950  		SetJSONContentType().
   951  		SetBody(bodyBytes)
   952  	var result2 Req
   953  	err = DefaultBinder().Bind(req.Req, &result2, nil)
   954  	if err != nil {
   955  		t.Error(err)
   956  	}
   957  	assert.DeepEqual(t, 1, result2.N.A)
   958  	assert.DeepEqual(t, 2, result2.N.B)
   959  	assert.DeepEqual(t, 0, result2.N.N2.C)
   960  	assert.DeepEqual(t, 0, result2.N.N2.D)
   961  }
   962  
   963  func TestValidate_MultipleValidate(t *testing.T) {
   964  	type Test1 struct {
   965  		A int `query:"a" vd:"$>10"`
   966  	}
   967  	req := newMockRequest().
   968  		SetRequestURI("http://foobar.com?a=9")
   969  	var result Test1
   970  	err := DefaultBinder().BindAndValidate(req.Req, &result, nil)
   971  	if err == nil {
   972  		t.Fatalf("expected an error, but get nil")
   973  	}
   974  }
   975  
   976  func TestBind_BindQuery(t *testing.T) {
   977  	type Req struct {
   978  		Q1 int `query:"q1"`
   979  		Q2 int
   980  		Q3 string
   981  		Q4 string
   982  		Q5 []int
   983  	}
   984  
   985  	req := newMockRequest().
   986  		SetRequestURI("http://foobar.com?q1=1&Q2=2&Q3=3&Q4=4&Q5=51&Q5=52")
   987  
   988  	var result Req
   989  
   990  	err := DefaultBinder().BindQuery(req.Req, &result)
   991  	if err != nil {
   992  		t.Error(err)
   993  	}
   994  	assert.DeepEqual(t, 1, result.Q1)
   995  	assert.DeepEqual(t, 2, result.Q2)
   996  	assert.DeepEqual(t, "3", result.Q3)
   997  	assert.DeepEqual(t, "4", result.Q4)
   998  	assert.DeepEqual(t, 51, result.Q5[0])
   999  	assert.DeepEqual(t, 52, result.Q5[1])
  1000  }
  1001  
  1002  func TestBind_LooseMode(t *testing.T) {
  1003  	bindConfig := &BindConfig{}
  1004  	bindConfig.LooseZeroMode = false
  1005  	binder := NewDefaultBinder(bindConfig)
  1006  	type Req struct {
  1007  		ID int `query:"id"`
  1008  	}
  1009  
  1010  	req := newMockRequest().
  1011  		SetRequestURI("http://foobar.com?id=")
  1012  
  1013  	var result Req
  1014  
  1015  	err := binder.Bind(req.Req, &result, nil)
  1016  	if err == nil {
  1017  		t.Fatal("expected err")
  1018  	}
  1019  	assert.DeepEqual(t, 0, result.ID)
  1020  
  1021  	bindConfig.LooseZeroMode = true
  1022  	binder = NewDefaultBinder(bindConfig)
  1023  	var result2 Req
  1024  
  1025  	err = binder.Bind(req.Req, &result2, nil)
  1026  	if err != nil {
  1027  		t.Error(err)
  1028  	}
  1029  	assert.DeepEqual(t, 0, result.ID)
  1030  }
  1031  
  1032  func TestBind_NonStruct(t *testing.T) {
  1033  	req := newMockRequest().
  1034  		SetRequestURI("http://foobar.com?id=1&id=2")
  1035  	var id interface{}
  1036  	err := DefaultBinder().Bind(req.Req, &id, nil)
  1037  	if err != nil {
  1038  		t.Error(err)
  1039  	}
  1040  
  1041  	err = DefaultBinder().BindAndValidate(req.Req, &id, nil)
  1042  	if err != nil {
  1043  		t.Error(err)
  1044  	}
  1045  }
  1046  
  1047  func TestBind_BindTag(t *testing.T) {
  1048  	type Req struct {
  1049  		Query  string
  1050  		Header string
  1051  		Path   string
  1052  		Form   string
  1053  	}
  1054  	req := newMockRequest().
  1055  		SetRequestURI("http://foobar.com?Query=query").
  1056  		SetHeader("Header", "header").
  1057  		SetPostArg("Form", "form")
  1058  	var params param.Params
  1059  	params = append(params, param.Param{
  1060  		Key:   "Path",
  1061  		Value: "path",
  1062  	})
  1063  	result := Req{}
  1064  
  1065  	// test query tag
  1066  	err := DefaultBinder().BindQuery(req.Req, &result)
  1067  	if err != nil {
  1068  		t.Error(err)
  1069  	}
  1070  	assert.DeepEqual(t, "query", result.Query)
  1071  
  1072  	// test header tag
  1073  	result = Req{}
  1074  	err = DefaultBinder().BindHeader(req.Req, &result)
  1075  	if err != nil {
  1076  		t.Error(err)
  1077  	}
  1078  	assert.DeepEqual(t, "header", result.Header)
  1079  
  1080  	// test form tag
  1081  	result = Req{}
  1082  	err = DefaultBinder().BindForm(req.Req, &result)
  1083  	if err != nil {
  1084  		t.Error(err)
  1085  	}
  1086  	assert.DeepEqual(t, "form", result.Form)
  1087  
  1088  	// test path tag
  1089  	result = Req{}
  1090  	err = DefaultBinder().BindPath(req.Req, &result, params)
  1091  	if err != nil {
  1092  		t.Error(err)
  1093  	}
  1094  	assert.DeepEqual(t, "path", result.Path)
  1095  
  1096  	// test json tag
  1097  	req = newMockRequest().
  1098  		SetRequestURI("http://foobar.com").
  1099  		SetJSONContentType().
  1100  		SetBody([]byte("{\n    \"Query\": \"query\",\n    \"Path\": \"path\",\n    \"Header\": \"header\",\n    \"Form\": \"form\"\n}"))
  1101  	result = Req{}
  1102  	err = DefaultBinder().BindJSON(req.Req, &result)
  1103  	if err != nil {
  1104  		t.Error(err)
  1105  	}
  1106  	assert.DeepEqual(t, "form", result.Form)
  1107  	assert.DeepEqual(t, "query", result.Query)
  1108  	assert.DeepEqual(t, "header", result.Header)
  1109  	assert.DeepEqual(t, "path", result.Path)
  1110  }
  1111  
  1112  func TestBind_BindAndValidate(t *testing.T) {
  1113  	type Req struct {
  1114  		ID int `query:"id" vd:"$>10"`
  1115  	}
  1116  	req := newMockRequest().
  1117  		SetRequestURI("http://foobar.com?id=12")
  1118  
  1119  	// test bindAndValidate
  1120  	var result Req
  1121  	err := BindAndValidate(req.Req, &result, nil)
  1122  	if err != nil {
  1123  		t.Error(err)
  1124  	}
  1125  	assert.DeepEqual(t, 12, result.ID)
  1126  
  1127  	// test bind
  1128  	result = Req{}
  1129  	err = Bind(req.Req, &result, nil)
  1130  	if err != nil {
  1131  		t.Error(err)
  1132  	}
  1133  	assert.DeepEqual(t, 12, result.ID)
  1134  
  1135  	// test validate
  1136  	req = newMockRequest().
  1137  		SetRequestURI("http://foobar.com?id=9")
  1138  	result = Req{}
  1139  	err = Bind(req.Req, &result, nil)
  1140  	if err != nil {
  1141  		t.Error(err)
  1142  	}
  1143  	err = Validate(result)
  1144  	if err == nil {
  1145  		t.Errorf("expect an error, but get nil")
  1146  	}
  1147  	assert.DeepEqual(t, 9, result.ID)
  1148  }
  1149  
  1150  func TestBind_FastPath(t *testing.T) {
  1151  	type Req struct {
  1152  		ID int `query:"id" vd:"$>10"`
  1153  	}
  1154  	req := newMockRequest().
  1155  		SetRequestURI("http://foobar.com?id=12")
  1156  
  1157  	// test bindAndValidate
  1158  	var result Req
  1159  	err := BindAndValidate(req.Req, &result, nil)
  1160  	if err != nil {
  1161  		t.Error(err)
  1162  	}
  1163  	assert.DeepEqual(t, 12, result.ID)
  1164  	// execute multiple times, test cache
  1165  	for i := 0; i < 10; i++ {
  1166  		result = Req{}
  1167  		err := BindAndValidate(req.Req, &result, nil)
  1168  		if err != nil {
  1169  			t.Error(err)
  1170  		}
  1171  		assert.DeepEqual(t, 12, result.ID)
  1172  	}
  1173  }
  1174  
  1175  func TestBind_NonPointer(t *testing.T) {
  1176  	type Req struct {
  1177  		ID int `query:"id" vd:"$>10"`
  1178  	}
  1179  	req := newMockRequest().
  1180  		SetRequestURI("http://foobar.com?id=12")
  1181  
  1182  	// test bindAndValidate
  1183  	var result Req
  1184  	err := BindAndValidate(req.Req, result, nil)
  1185  	if err == nil {
  1186  		t.Error("expect an error, but get nil")
  1187  	}
  1188  
  1189  	err = Bind(req.Req, result, nil)
  1190  	if err == nil {
  1191  		t.Error("expect an error, but get nil")
  1192  	}
  1193  }
  1194  
  1195  func TestBind_PreBind(t *testing.T) {
  1196  	type Req struct {
  1197  		Query  string
  1198  		Header string
  1199  		Path   string
  1200  		Form   string
  1201  	}
  1202  	// test json tag
  1203  	req := newMockRequest().
  1204  		SetRequestURI("http://foobar.com").
  1205  		SetJSONContentType().
  1206  		SetBody([]byte("\n    \"Query\": \"query\",\n    \"Path\": \"path\",\n    \"Header\": \"header\",\n    \"Form\": \"form\"\n}"))
  1207  	result := Req{}
  1208  	err := DefaultBinder().Bind(req.Req, &result, nil)
  1209  	if err == nil {
  1210  		t.Error("expect an error, but get nil")
  1211  	}
  1212  	err = DefaultBinder().BindAndValidate(req.Req, &result, nil)
  1213  	if err == nil {
  1214  		t.Error("expect an error, but get nil")
  1215  	}
  1216  }
  1217  
  1218  func TestBind_BindProtobuf(t *testing.T) {
  1219  	data := testdata.HertzReq{Name: "hertz"}
  1220  	body, err := proto.Marshal(&data)
  1221  	if err != nil {
  1222  		t.Fatal(err)
  1223  	}
  1224  	req := newMockRequest().
  1225  		SetRequestURI("http://foobar.com").
  1226  		SetProtobufContentType().
  1227  		SetBody(body)
  1228  
  1229  	result := testdata.HertzReq{}
  1230  	err = DefaultBinder().BindAndValidate(req.Req, &result, nil)
  1231  	if err != nil {
  1232  		t.Error(err)
  1233  	}
  1234  	assert.DeepEqual(t, "hertz", result.Name)
  1235  
  1236  	result = testdata.HertzReq{}
  1237  	err = DefaultBinder().BindProtobuf(req.Req, &result)
  1238  	if err != nil {
  1239  		t.Error(err)
  1240  	}
  1241  	assert.DeepEqual(t, "hertz", result.Name)
  1242  }
  1243  
  1244  func TestBind_PointerStruct(t *testing.T) {
  1245  	bindConfig := &BindConfig{}
  1246  	bindConfig.DisableStructFieldResolve = false
  1247  	binder := NewDefaultBinder(bindConfig)
  1248  	type Foo struct {
  1249  		F1 string `query:"F1"`
  1250  	}
  1251  	type Bar struct {
  1252  		B1 **Foo `query:"B1,required"`
  1253  	}
  1254  	query := make(url.Values)
  1255  	query.Add("B1", "{\n    \"F1\": \"111\"\n}")
  1256  
  1257  	var result Bar
  1258  	req := newMockRequest().
  1259  		SetRequestURI(fmt.Sprintf("http://foobar.com?%s", query.Encode()))
  1260  
  1261  	err := binder.Bind(req.Req, &result, nil)
  1262  	if err != nil {
  1263  		t.Error(err)
  1264  	}
  1265  	assert.DeepEqual(t, "111", (**result.B1).F1)
  1266  
  1267  	result = Bar{}
  1268  	req = newMockRequest().
  1269  		SetRequestURI(fmt.Sprintf("http://foobar.com?%s&F1=222", query.Encode()))
  1270  	err = binder.Bind(req.Req, &result, nil)
  1271  	if err != nil {
  1272  		t.Error(err)
  1273  	}
  1274  	assert.DeepEqual(t, "222", (**result.B1).F1)
  1275  }
  1276  
  1277  func TestBind_StructRequired(t *testing.T) {
  1278  	bindConfig := &BindConfig{}
  1279  	bindConfig.DisableStructFieldResolve = false
  1280  	binder := NewDefaultBinder(bindConfig)
  1281  	type Foo struct {
  1282  		F1 string `query:"F1"`
  1283  	}
  1284  	type Bar struct {
  1285  		B1 **Foo `query:"B1,required"`
  1286  	}
  1287  
  1288  	var result Bar
  1289  	req := newMockRequest().
  1290  		SetRequestURI("http://foobar.com")
  1291  
  1292  	err := binder.Bind(req.Req, &result, nil)
  1293  	if err == nil {
  1294  		t.Error("expect an error, but get nil")
  1295  	}
  1296  
  1297  	type Bar2 struct {
  1298  		B1 **Foo `query:"B1"`
  1299  	}
  1300  	var result2 Bar2
  1301  	req = newMockRequest().
  1302  		SetRequestURI("http://foobar.com")
  1303  
  1304  	err = binder.Bind(req.Req, &result2, nil)
  1305  	if err != nil {
  1306  		t.Error(err)
  1307  	}
  1308  }
  1309  
  1310  func TestBind_StructErrorToWarn(t *testing.T) {
  1311  	bindConfig := &BindConfig{}
  1312  	bindConfig.DisableStructFieldResolve = false
  1313  	binder := NewDefaultBinder(bindConfig)
  1314  	type Foo struct {
  1315  		F1 string `query:"F1"`
  1316  	}
  1317  	type Bar struct {
  1318  		B1 **Foo `query:"B1,required"`
  1319  	}
  1320  
  1321  	var result Bar
  1322  	req := newMockRequest().
  1323  		SetRequestURI("http://foobar.com?B1=111&F1=222")
  1324  
  1325  	err := binder.Bind(req.Req, &result, nil)
  1326  	// transfer 'unmarsahl err' to 'warn'
  1327  	if err != nil {
  1328  		t.Error(err)
  1329  	}
  1330  	assert.DeepEqual(t, "222", (**result.B1).F1)
  1331  
  1332  	type Bar2 struct {
  1333  		B1 Foo `query:"B1,required"`
  1334  	}
  1335  	var result2 Bar2
  1336  	err = binder.Bind(req.Req, &result2, nil)
  1337  	// transfer 'unmarsahl err' to 'warn'
  1338  	if err != nil {
  1339  		t.Error(err)
  1340  	}
  1341  	assert.DeepEqual(t, "222", result2.B1.F1)
  1342  }
  1343  
  1344  func TestBind_DisallowUnknownFieldsConfig(t *testing.T) {
  1345  	bindConfig := &BindConfig{}
  1346  	bindConfig.EnableDecoderDisallowUnknownFields = true
  1347  	binder := NewDefaultBinder(bindConfig)
  1348  	type FooStructUseNumber struct {
  1349  		Foo interface{} `json:"foo"`
  1350  	}
  1351  	req := newMockRequest().
  1352  		SetRequestURI("http://foobar.com").
  1353  		SetJSONContentType().
  1354  		SetBody([]byte(`{"foo": 123,"bar": "456"}`))
  1355  	var result FooStructUseNumber
  1356  
  1357  	err := binder.BindJSON(req.Req, &result)
  1358  	if err == nil {
  1359  		t.Errorf("expected an error, but get nil")
  1360  	}
  1361  }
  1362  
  1363  func TestBind_UseNumberConfig(t *testing.T) {
  1364  	bindConfig := &BindConfig{}
  1365  	bindConfig.EnableDecoderUseNumber = true
  1366  	binder := NewDefaultBinder(bindConfig)
  1367  	type FooStructUseNumber struct {
  1368  		Foo interface{} `json:"foo"`
  1369  	}
  1370  	req := newMockRequest().
  1371  		SetRequestURI("http://foobar.com").
  1372  		SetJSONContentType().
  1373  		SetBody([]byte(`{"foo": 123}`))
  1374  	var result FooStructUseNumber
  1375  
  1376  	err := binder.BindJSON(req.Req, &result)
  1377  	if err != nil {
  1378  		t.Error(err)
  1379  	}
  1380  	v, err := result.Foo.(json.Number).Int64()
  1381  	if err != nil {
  1382  		t.Error(err)
  1383  	}
  1384  	assert.DeepEqual(t, int64(123), v)
  1385  }
  1386  
  1387  func TestBind_InterfaceType(t *testing.T) {
  1388  	type Bar struct {
  1389  		B1 interface{} `query:"B1"`
  1390  	}
  1391  
  1392  	var result Bar
  1393  	query := make(url.Values)
  1394  	query.Add("B1", `{"B1":"111"}`)
  1395  	req := newMockRequest().
  1396  		SetRequestURI(fmt.Sprintf("http://foobar.com?%s", query.Encode()))
  1397  	err := DefaultBinder().Bind(req.Req, &result, nil)
  1398  	if err != nil {
  1399  		t.Error(err)
  1400  	}
  1401  
  1402  	type Bar2 struct {
  1403  		B2 *interface{} `query:"B1"`
  1404  	}
  1405  
  1406  	var result2 Bar2
  1407  	err = DefaultBinder().Bind(req.Req, &result2, nil)
  1408  	if err != nil {
  1409  		t.Error(err)
  1410  	}
  1411  }
  1412  
  1413  func Test_BindHeaderNormalize(t *testing.T) {
  1414  	type Req struct {
  1415  		Header string `header:"h"`
  1416  	}
  1417  
  1418  	req := newMockRequest().
  1419  		SetRequestURI("http://foobar.com").
  1420  		SetHeaders("h", "header")
  1421  	var result Req
  1422  
  1423  	err := DefaultBinder().Bind(req.Req, &result, nil)
  1424  	if err != nil {
  1425  		t.Error(err)
  1426  	}
  1427  	assert.DeepEqual(t, "header", result.Header)
  1428  	req = newMockRequest().
  1429  		SetRequestURI("http://foobar.com").
  1430  		SetHeaders("H", "header")
  1431  	err = DefaultBinder().Bind(req.Req, &result, nil)
  1432  	if err != nil {
  1433  		t.Error(err)
  1434  	}
  1435  	assert.DeepEqual(t, "header", result.Header)
  1436  
  1437  	type Req2 struct {
  1438  		Header string `header:"H"`
  1439  	}
  1440  
  1441  	req2 := newMockRequest().
  1442  		SetRequestURI("http://foobar.com").
  1443  		SetHeaders("h", "header")
  1444  	var result2 Req2
  1445  
  1446  	err2 := DefaultBinder().Bind(req2.Req, &result2, nil)
  1447  	if err != nil {
  1448  		t.Error(err2)
  1449  	}
  1450  	assert.DeepEqual(t, "header", result2.Header)
  1451  	req2 = newMockRequest().
  1452  		SetRequestURI("http://foobar.com").
  1453  		SetHeaders("H", "header")
  1454  	err2 = DefaultBinder().Bind(req2.Req, &result2, nil)
  1455  	if err2 != nil {
  1456  		t.Error(err2)
  1457  	}
  1458  	assert.DeepEqual(t, "header", result2.Header)
  1459  
  1460  	type Req3 struct {
  1461  		Header string `header:"h"`
  1462  	}
  1463  
  1464  	// without normalize, the header key & tag key need to be consistent
  1465  	req3 := newMockRequest().
  1466  		SetRequestURI("http://foobar.com")
  1467  	req3.Req.Header.DisableNormalizing()
  1468  	req3.SetHeaders("h", "header")
  1469  	var result3 Req3
  1470  	err3 := DefaultBinder().Bind(req3.Req, &result3, nil)
  1471  	if err3 != nil {
  1472  		t.Error(err3)
  1473  	}
  1474  	assert.DeepEqual(t, "header", result3.Header)
  1475  	req3 = newMockRequest().
  1476  		SetRequestURI("http://foobar.com")
  1477  	req3.Req.Header.DisableNormalizing()
  1478  	req3.SetHeaders("H", "header")
  1479  	result3 = Req3{}
  1480  	err3 = DefaultBinder().Bind(req3.Req, &result3, nil)
  1481  	if err3 != nil {
  1482  		t.Error(err3)
  1483  	}
  1484  	assert.DeepEqual(t, "", result3.Header)
  1485  }
  1486  
  1487  type ValidateError struct {
  1488  	ErrType, FailField, Msg string
  1489  }
  1490  
  1491  // Error implements error interface.
  1492  func (e *ValidateError) Error() string {
  1493  	if e.Msg != "" {
  1494  		return e.ErrType + ": expr_path=" + e.FailField + ", cause=" + e.Msg
  1495  	}
  1496  	return e.ErrType + ": expr_path=" + e.FailField + ", cause=invalid"
  1497  }
  1498  
  1499  func Test_ValidatorErrorFactory(t *testing.T) {
  1500  	type TestBind struct {
  1501  		A string `query:"a,required"`
  1502  	}
  1503  
  1504  	r := protocol.NewRequest("GET", "/foo", nil)
  1505  	r.SetRequestURI("/foo/bar?b=20")
  1506  	CustomValidateErrFunc := func(failField, msg string) error {
  1507  		err := ValidateError{
  1508  			ErrType:   "validateErr",
  1509  			FailField: "[validateFailField]: " + failField,
  1510  			Msg:       "[validateErrMsg]: " + msg,
  1511  		}
  1512  
  1513  		return &err
  1514  	}
  1515  
  1516  	validateConfig := NewValidateConfig()
  1517  	validateConfig.SetValidatorErrorFactory(CustomValidateErrFunc)
  1518  	validator := NewValidator(validateConfig)
  1519  
  1520  	var req TestBind
  1521  	err := Bind(r, &req, nil)
  1522  	if err == nil {
  1523  		t.Fatalf("unexpected nil, expected an error")
  1524  	}
  1525  	assert.DeepEqual(t, "'a' field is a 'required' parameter, but the request does not have this parameter", err.Error())
  1526  
  1527  	type TestValidate struct {
  1528  		B int `query:"b" vd:"$>100"`
  1529  	}
  1530  
  1531  	var reqValidate TestValidate
  1532  	err = Bind(r, &reqValidate, nil)
  1533  	if err != nil {
  1534  		t.Fatalf("unexpected error: %v", err)
  1535  	}
  1536  	err = validator.ValidateStruct(&reqValidate)
  1537  	if err == nil {
  1538  		t.Fatalf("unexpected nil, expected an error")
  1539  	}
  1540  	assert.DeepEqual(t, "validateErr: expr_path=[validateFailField]: B, cause=[validateErrMsg]: ", err.Error())
  1541  }
  1542  
  1543  // Test_Issue964 used to the cover issue for time.Time
  1544  func Test_Issue964(t *testing.T) {
  1545  	type CreateReq struct {
  1546  		StartAt *time.Time `json:"startAt"`
  1547  	}
  1548  	r := newMockRequest().SetBody([]byte("{\n  \"startAt\": \"2006-01-02T15:04:05+07:00\"\n}")).SetJSONContentType()
  1549  	var req CreateReq
  1550  	err := DefaultBinder().BindAndValidate(r.Req, &req, nil)
  1551  	if err != nil {
  1552  		t.Error(err)
  1553  	}
  1554  	assert.DeepEqual(t, "2006-01-02 15:04:05 +0700 +0700", req.StartAt.String())
  1555  	r = newMockRequest()
  1556  	req = CreateReq{}
  1557  	err = DefaultBinder().BindAndValidate(r.Req, &req, nil)
  1558  	if err != nil {
  1559  		t.Error(err)
  1560  	}
  1561  	if req.StartAt != nil {
  1562  		t.Error("expected nil")
  1563  	}
  1564  }
  1565  
  1566  type reqSameType struct {
  1567  	Parent   *reqSameType  `json:"parent"`
  1568  	Children []reqSameType `json:"children"`
  1569  	Foo1     reqSameType2  `json:"foo1"`
  1570  	A        string        `json:"a"`
  1571  }
  1572  
  1573  type reqSameType2 struct {
  1574  	Foo1 *reqSameType `json:"foo1"`
  1575  }
  1576  
  1577  func TestBind_Issue1015(t *testing.T) {
  1578  	req := newMockRequest().
  1579  		SetJSONContentType().
  1580  		SetBody([]byte(`{"parent":{"parent":{}, "children":[{},{}], "foo1":{"foo1":{}}}, "children":[{},{}], "a":"asd"}`))
  1581  
  1582  	var result reqSameType
  1583  
  1584  	err := DefaultBinder().Bind(req.Req, &result, nil)
  1585  	if err != nil {
  1586  		t.Error(err)
  1587  	}
  1588  	assert.NotNil(t, result.Parent)
  1589  	assert.NotNil(t, result.Parent.Parent)
  1590  	assert.Nil(t, result.Parent.Parent.Parent)
  1591  	assert.NotNil(t, result.Parent.Children)
  1592  	assert.DeepEqual(t, 2, len(result.Parent.Children))
  1593  	assert.NotNil(t, result.Parent.Foo1.Foo1)
  1594  	assert.DeepEqual(t, "", result.Parent.A)
  1595  	assert.DeepEqual(t, 2, len(result.Children))
  1596  	assert.Nil(t, result.Foo1.Foo1)
  1597  	assert.DeepEqual(t, "asd", result.A)
  1598  }
  1599  
  1600  func TestBind_JSONWithDefault(t *testing.T) {
  1601  	type Req struct {
  1602  		J1 string `json:"j1" default:"j1default"`
  1603  	}
  1604  
  1605  	req := newMockRequest().
  1606  		SetJSONContentType().
  1607  		SetBody([]byte(`{"j1":"j1"}`))
  1608  	var result Req
  1609  	err := DefaultBinder().Bind(req.Req, &result, nil)
  1610  	if err != nil {
  1611  		t.Error(err)
  1612  	}
  1613  	assert.DeepEqual(t, "j1", result.J1)
  1614  
  1615  	result = Req{}
  1616  	req = newMockRequest().
  1617  		SetJSONContentType().
  1618  		SetBody([]byte(`{"j2":"j2"}`))
  1619  	err = DefaultBinder().Bind(req.Req, &result, nil)
  1620  	if err != nil {
  1621  		t.Error(err)
  1622  	}
  1623  	assert.DeepEqual(t, "j1default", result.J1)
  1624  }
  1625  
  1626  func TestBind_WithoutPreBindForTag(t *testing.T) {
  1627  	type BaseQuery struct {
  1628  		Action  string `query:"Action" binding:"required"`
  1629  		Version string `query:"Version" binding:"required"`
  1630  	}
  1631  
  1632  	req := newMockRequest().
  1633  		SetJSONContentType().
  1634  		SetRequestURI("http://foobar.com/?Action=action&Version=version").
  1635  		SetBody([]byte(``))
  1636  
  1637  	var result BaseQuery
  1638  
  1639  	err := DefaultBinder().BindQuery(req.Req, &result)
  1640  	if err != nil {
  1641  		t.Error(err)
  1642  	}
  1643  	assert.DeepEqual(t, "action", result.Action)
  1644  	assert.DeepEqual(t, "version", result.Version)
  1645  }
  1646  
  1647  func TestBind_NormalizeContentType(t *testing.T) {
  1648  	type BaseQuery struct {
  1649  		Action  string `json:"action" binding:"required"`
  1650  		Version string `json:"version" binding:"required"`
  1651  	}
  1652  
  1653  	req := newMockRequest().
  1654  		SetHeader("Content-Type", "ApplicAtion/json").
  1655  		SetRequestURI("http://foobar.com/?Action=action&Version=version").
  1656  		SetBody([]byte(`{"action":"action", "version":"version"}`))
  1657  
  1658  	var result BaseQuery
  1659  
  1660  	err := DefaultBinder().BindQuery(req.Req, &result)
  1661  	if err != nil {
  1662  		t.Error(err)
  1663  	}
  1664  	assert.DeepEqual(t, "action", result.Action)
  1665  	assert.DeepEqual(t, "version", result.Version)
  1666  }
  1667  
  1668  func Benchmark_Binding(b *testing.B) {
  1669  	type Req struct {
  1670  		Version string `path:"v"`
  1671  		ID      int    `query:"id"`
  1672  		Header  string `header:"h"`
  1673  		Form    string `form:"f"`
  1674  	}
  1675  
  1676  	req := newMockRequest().
  1677  		SetRequestURI("http://foobar.com?id=12").
  1678  		SetHeaders("H", "header").
  1679  		SetPostArg("f", "form").
  1680  		SetUrlEncodeContentType()
  1681  
  1682  	var params param.Params
  1683  	params = append(params, param.Param{
  1684  		Key:   "v",
  1685  		Value: "1",
  1686  	})
  1687  
  1688  	b.ResetTimer()
  1689  	for i := 0; i < b.N; i++ {
  1690  		var result Req
  1691  		err := DefaultBinder().Bind(req.Req, &result, params)
  1692  		if err != nil {
  1693  			b.Error(err)
  1694  		}
  1695  		if result.ID != 12 {
  1696  			b.Error("Id failed")
  1697  		}
  1698  		if result.Form != "form" {
  1699  			b.Error("form failed")
  1700  		}
  1701  		if result.Header != "header" {
  1702  			b.Error("header failed")
  1703  		}
  1704  		if result.Version != "1" {
  1705  			b.Error("path failed")
  1706  		}
  1707  	}
  1708  }