github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/conv/j2t/conv_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   */
    16  
    17  package j2t
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/base64"
    23  	"encoding/json"
    24  	"fmt"
    25  	"io/ioutil"
    26  	"math"
    27  	stdh "net/http"
    28  	"net/url"
    29  	"os"
    30  	"runtime"
    31  	"runtime/debug"
    32  	"strconv"
    33  	"strings"
    34  	"testing"
    35  	"time"
    36  	"unsafe"
    37  
    38  	sjson "github.com/bytedance/sonic/ast"
    39  	"github.com/cloudwego/dynamicgo/conv"
    40  	"github.com/cloudwego/dynamicgo/http"
    41  	"github.com/cloudwego/dynamicgo/internal/native"
    42  	"github.com/cloudwego/dynamicgo/internal/native/types"
    43  	"github.com/cloudwego/dynamicgo/internal/rt"
    44  	"github.com/cloudwego/dynamicgo/meta"
    45  	"github.com/cloudwego/dynamicgo/testdata/kitex_gen/example3"
    46  	"github.com/cloudwego/dynamicgo/testdata/kitex_gen/null"
    47  	"github.com/cloudwego/dynamicgo/testdata/sample"
    48  	"github.com/cloudwego/dynamicgo/thrift"
    49  	"github.com/cloudwego/dynamicgo/thrift/annotation"
    50  	"github.com/cloudwego/dynamicgo/thrift/base"
    51  	"github.com/stretchr/testify/require"
    52  )
    53  
    54  var (
    55  	debugAsyncGC = os.Getenv("SONIC_NO_ASYNC_GC") == ""
    56  )
    57  
    58  func TestMain(m *testing.M) {
    59  	go func() {
    60  		if !debugAsyncGC {
    61  			return
    62  		}
    63  		println("Begin GC looping...")
    64  		for {
    65  			runtime.GC()
    66  			debug.FreeOSMemory()
    67  		}
    68  	}()
    69  	time.Sleep(time.Millisecond)
    70  	annotation.InitAGWAnnos()
    71  	m.Run()
    72  }
    73  
    74  const (
    75  	exampleIDLPath = "../../testdata/idl/example3.thrift"
    76  	nullIDLPath    = "../../testdata/idl/null.thrift"
    77  	exampleJSON    = "../../testdata/data/example3req.json"
    78  	nullJSON       = "../../testdata/data/null_pass.json"
    79  	nullerrJSON    = "../../testdata/data/null_err.json"
    80  )
    81  
    82  
    83  func TestCases(t *testing.T) {
    84  	var tests = []struct{
    85  		name string
    86  		idl string
    87  		includes map[string]string
    88  		js string
    89  		opt conv.Options
    90  		want interface{}
    91  		err error
    92  	}{
    93  		{
    94  			name: "int2double_vm",
    95  			idl: 
    96  `struct Req {
    97  	1: optional double body (api.js_conv=""), 
    98  }
    99  
   100  service SVR {
   101  	void Method(1: Req req)
   102  }	
   103  `,
   104  			includes: nil,
   105  			js: `{"body":"-1"}`,
   106  			opt: conv.Options{},
   107  			want: map[string]interface{}{
   108  				"body": float64(-1),
   109  			},
   110  		},
   111  		{
   112  			name: "int2double",
   113  			idl: 
   114  `struct Req {
   115  	1: optional double body, 
   116  }
   117  
   118  service SVR {
   119  	void Method(1: Req req)
   120  }	
   121  `,
   122  			includes: nil,
   123  			js: `{"body":-2}`,
   124  			opt: conv.Options{EnableValueMapping: true},
   125  			want: map[string]interface{}{
   126  				"body": float64(-2),
   127  			},
   128  		},
   129  	}
   130  	for _, c := range tests {
   131  		t.Run(c.name, func(t *testing.T) {
   132  			ctx := context.Background()
   133  			svc, err := thrift.NewDefaultOptions().NewDescritorFromContent(ctx, "a.thrift", c.idl, c.includes, false)
   134  			if err != nil {
   135  				t.Fatal(err)
   136  			}
   137  			desc := svc.Functions()["Method"].Request().Struct().FieldById(1).Type()
   138  			cv := NewBinaryConv(conv.Options{
   139  				EnableValueMapping: true,
   140  			})
   141  			out, err := cv.Do(ctx, desc, []byte(c.js))
   142  			if err != nil {
   143  				if c.err == nil || c.err.Error() == err.Error() {
   144  					t.Fatal(err)
   145  				}
   146  			}
   147  			v, err := thrift.NewBinaryProtocol(out).ReadAnyWithDesc(desc, false, false, false, true)
   148  			if err != nil {
   149  				if c.err == nil || c.err.Error() == err.Error() {
   150  					t.Fatal(err)
   151  				}
   152  			}
   153  			require.Equal(t, c.want, v)
   154  		})
   155  	}
   156  }
   157  
   158  
   159  func TestConvJSON2Thrift(t *testing.T) {
   160  	desc := getExampleDesc()
   161  	data := getExampleData()
   162  	cv := NewBinaryConv(conv.Options{})
   163  	ctx := context.Background()
   164  	out, err := cv.Do(ctx, desc, data)
   165  	require.Nil(t, err)
   166  	exp := example3.NewExampleReq()
   167  	err = json.Unmarshal(data, exp)
   168  	require.Nil(t, err)
   169  	act := example3.NewExampleReq()
   170  	_, err = act.FastRead(out)
   171  	require.Nil(t, err)
   172  	require.Equal(t, exp, act)
   173  }
   174  
   175  func TestConvHTTP2Thrift(t *testing.T) {
   176  	desc := getExampleDesc()
   177  	data := getExampleData()
   178  	exp := example3.NewExampleReq()
   179  	err := json.Unmarshal(data, exp)
   180  	require.Nil(t, err)
   181  	req := getExampleReq(exp, true, data)
   182  	cv := NewBinaryConv(conv.Options{
   183  		EnableHttpMapping: true,
   184  	})
   185  	ctx := context.Background()
   186  	ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
   187  	out, err := cv.Do(ctx, desc, data)
   188  	require.NoError(t, err)
   189  
   190  	act := example3.NewExampleReq()
   191  	_, err = act.FastRead(out)
   192  	require.Nil(t, err)
   193  	require.Equal(t, exp, act)
   194  }
   195  
   196  func getExampleDesc() *thrift.TypeDescriptor {
   197  	opts := thrift.Options{}
   198  	svc, err := opts.NewDescritorFromPath(context.Background(), exampleIDLPath)
   199  	if err != nil {
   200  		panic(err)
   201  	}
   202  	return svc.Functions()["ExampleMethod"].Request().Struct().FieldById(1).Type()
   203  }
   204  
   205  func getErrorExampleDesc() *thrift.TypeDescriptor {
   206  	opts := thrift.Options{}
   207  	svc, err := opts.NewDescritorFromPath(context.Background(), exampleIDLPath)
   208  	if err != nil {
   209  		panic(err)
   210  	}
   211  	return svc.Functions()["ErrorMethod"].Request().Struct().FieldById(1).Type()
   212  }
   213  
   214  func getExampleInt2FloatDesc() *thrift.TypeDescriptor {
   215  	opts := thrift.Options{}
   216  	svc, err := opts.NewDescritorFromPath(context.Background(), exampleIDLPath)
   217  	if err != nil {
   218  		panic(err)
   219  	}
   220  	return svc.Functions()["Int2FloatMethod"].Request().Struct().FieldById(1).Type()
   221  }
   222  
   223  func getExampleJSONStringDesc() *thrift.TypeDescriptor {
   224  	opts := thrift.Options{}
   225  	svc, err := opts.NewDescritorFromPath(context.Background(), exampleIDLPath)
   226  	if err != nil {
   227  		panic(err)
   228  	}
   229  	return svc.Functions()["JSONStringMethod"].Request().Struct().FieldById(1).Type()
   230  }
   231  
   232  func getExampleFallbackDesc() *thrift.TypeDescriptor {
   233  	opts := thrift.Options{}
   234  	svc, err := opts.NewDescritorFromPath(context.Background(), exampleIDLPath)
   235  	if err != nil {
   236  		panic(err)
   237  	}
   238  	return svc.Functions()["FallbackMethod"].Request().Struct().FieldById(1).Type()
   239  }
   240  
   241  func getExampleDescByName(method string, req bool, opts thrift.Options) *thrift.TypeDescriptor {
   242  	svc, err := opts.NewDescritorFromPath(context.Background(), exampleIDLPath)
   243  	if err != nil {
   244  		panic(err)
   245  	}
   246  	if req {
   247  		return svc.Functions()[method].Request().Struct().Fields()[0].Type()
   248  	} else {
   249  		return svc.Functions()[method].Response().Struct().Fields()[0].Type()
   250  	}
   251  }
   252  
   253  func getExampleData() []byte {
   254  	out, err := ioutil.ReadFile(exampleJSON)
   255  	if err != nil {
   256  		panic(err)
   257  	}
   258  	return out
   259  }
   260  
   261  func getExampleReq(exp *example3.ExampleReq, setIs bool, body []byte) *http.HTTPRequest {
   262  	f := -1.00001
   263  	x := true
   264  	q := []string{"1", "2", "3"}
   265  	p := "<>"
   266  	is := "abcd"
   267  	uv := url.Values{
   268  		"query": []string{strings.Join(q, ",")},
   269  	}
   270  	if setIs {
   271  		uv.Add("inner_query", is)
   272  		exp.InnerBase.InnerQuery = is
   273  		exp.InnerBase.ListInnerBase[0].InnerQuery = is
   274  		exp.InnerBase.MapStringInnerBase["innerx"].InnerQuery = is
   275  	}
   276  
   277  	uri := "http://localhost:8888/root?" + uv.Encode()
   278  	hr, err := stdh.NewRequest("POST", uri, bytes.NewBuffer(body))
   279  	if err != nil {
   280  		panic(err)
   281  	}
   282  	hr.Header.Set("Content-Type", "application/json")
   283  	req, err := http.NewHTTPRequestFromStdReq(hr)
   284  	if err != nil {
   285  		panic(err)
   286  	}
   287  	req.Params.Set("path", p)
   288  	req.Request.Header.Add("heeader", strconv.FormatBool(x))
   289  	req.AddCookie(&stdh.Cookie{Name: "cookie", Value: strconv.FormatFloat(f, 'f', -1, 64)})
   290  	if setIs {
   291  		req.Request.Header.Add("inner_string", is)
   292  		exp.InnerBase.ListInnerBase[0].String_ = is
   293  		exp.InnerBase.MapStringInnerBase["innerx"].String_ = is
   294  		exp.InnerBase.String_ = is
   295  	}
   296  	exp.Path = p
   297  	exp.Query = q
   298  	exp.Header = &x
   299  	exp.Cookie = &f
   300  	exp.RawUri = uri
   301  	return req
   302  }
   303  
   304  func getExampleJSONStringReq(exp *example3.ExampleJSONString) *http.HTTPRequest {
   305  	j := `{"a":"1","b":2}`
   306  	x := "{}"
   307  	a := `["1","2","3"]`
   308  	b := `[1,2,3]`
   309  	c := `{"1":"1","2":"2","3":"3"}`
   310  
   311  	qs := url.Values{}
   312  	qs.Add("query", j)
   313  	qs.Add("query2", a)
   314  	hr, err := stdh.NewRequest("POST", "http://localhost:8888/root?"+qs.Encode(), bytes.NewBuffer(nil))
   315  	if err != nil {
   316  		panic(err)
   317  	}
   318  	req := &http.HTTPRequest{
   319  		Request: hr,
   320  	}
   321  	req.AddCookie(&stdh.Cookie{Name: "cookie", Value: x})
   322  	req.AddCookie(&stdh.Cookie{Name: "cookie2", Value: b})
   323  	req.Request.Header.Set("header", j)
   324  	req.Request.Header.Set("header2", c)
   325  
   326  	_ = json.Unmarshal([]byte(j), &exp.Query)
   327  	_ = json.Unmarshal([]byte(a), &exp.Query2)
   328  	_ = json.Unmarshal([]byte(x), &exp.Cookie)
   329  	_ = json.Unmarshal([]byte(b), &exp.Cookie2)
   330  	_ = json.Unmarshal([]byte(j), &exp.Header)
   331  	_ = json.Unmarshal([]byte(c), &exp.Header2)
   332  	return req
   333  }
   334  
   335  func getNullDesc() *thrift.TypeDescriptor {
   336  	opts := thrift.Options{}
   337  	svc, err := opts.NewDescritorFromPath(context.Background(), nullIDLPath)
   338  	if err != nil {
   339  		panic(err)
   340  	}
   341  	return svc.Functions()["NullTest"].Request().Struct().FieldById(1).Type()
   342  }
   343  
   344  func getNullData() []byte {
   345  	out, err := ioutil.ReadFile(nullJSON)
   346  	if err != nil {
   347  		panic(err)
   348  	}
   349  	return out
   350  }
   351  
   352  func getNullErrData() []byte {
   353  	out, err := ioutil.ReadFile(nullerrJSON)
   354  	if err != nil {
   355  		panic(err)
   356  	}
   357  	return out
   358  }
   359  
   360  func TestWriteDefault(t *testing.T) {
   361  	desc := getExampleDesc()
   362  	data := []byte(`{"Path":"<>"}`)
   363  	exp := example3.NewExampleReq()
   364  	data2 := []byte(`{"Path":"<>","Base":{}}`)
   365  	exp.InnerBase = sample.GetEmptyInnerBase3()
   366  	err := json.Unmarshal(data2, exp)
   367  	require.Nil(t, err)
   368  	req := getExampleReq(exp, false, data)
   369  	cv := NewBinaryConv(conv.Options{
   370  		WriteDefaultField: true,
   371  		EnableHttpMapping: true,
   372  	})
   373  	ctx := context.Background()
   374  	ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
   375  	out, err := cv.Do(ctx, desc, data)
   376  	require.Nil(t, err)
   377  	act := example3.NewExampleReq()
   378  	_, err = act.FastRead(out)
   379  	require.Nil(t, err)
   380  	require.Equal(t, exp, act)
   381  }
   382  
   383  func TestWriteRequired(t *testing.T) {
   384  	desc := getExampleDesc()
   385  	data := []byte(`{}`)
   386  	t.Run("JSON", func(t *testing.T) {
   387  		exp := example3.NewExampleReq()
   388  		data2 := []byte(`{"Path":""}`)
   389  		err := json.Unmarshal(data2, exp)
   390  		require.Nil(t, err)
   391  		cv := NewBinaryConv(conv.Options{
   392  			WriteRequireField: true,
   393  		})
   394  		ctx := context.Background()
   395  		out, err := cv.Do(ctx, desc, data)
   396  		require.Nil(t, err)
   397  		act := example3.NewExampleReq()
   398  		_, err = act.FastRead(out)
   399  		require.Nil(t, err)
   400  		require.Equal(t, exp, act)
   401  	})
   402  	t.Run("http-mapping", func(t *testing.T) {
   403  		exp := example3.NewExampleReq()
   404  		exp.InnerBase = sample.GetEmptyInnerBase3()
   405  		data2 := []byte(`{"Path":"","Base":{}}`)
   406  		err := json.Unmarshal(data2, exp)
   407  		require.Nil(t, err)
   408  		hr, err := stdh.NewRequest("POST", "http://localhost:8888/root", bytes.NewBuffer(data))
   409  		require.NoError(t, err)
   410  		exp.RawUri = hr.URL.String()
   411  		req, err := http.NewHTTPRequestFromStdReq(hr)
   412  		require.NoError(t, err)
   413  		cv := NewBinaryConv(conv.Options{
   414  			WriteRequireField: true,
   415  			WriteDefaultField: true,
   416  			EnableHttpMapping: true,
   417  		})
   418  		ctx := context.Background()
   419  		ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
   420  		out, err := cv.Do(ctx, desc, data)
   421  		require.Nil(t, err)
   422  		act := example3.NewExampleReq()
   423  		_, err = act.FastRead(out)
   424  		require.Nil(t, err)
   425  		require.Equal(t, exp, act)
   426  	})
   427  }
   428  
   429  func TestBodyFallbackToHttp(t *testing.T) {
   430  	desc := getExampleDesc()
   431  	data := []byte(`{}`)
   432  	hr, err := stdh.NewRequest("POST", "http://localhost:8888/root?Msg=a&Subfix=1", bytes.NewBuffer(nil))
   433  	hr.Header.Set("Base", `{"LogID":"c"}`)
   434  	hr.Header.Set("Path", `b`)
   435  	// NOTICE: optional field will be ignored
   436  	hr.Header.Set("Extra", `{"x":"y"}`)
   437  	require.NoError(t, err)
   438  	req := &http.HTTPRequest{
   439  		Request: hr,
   440  		BodyMap: map[string]string{
   441  			"InnerBase": `{"Bool":true}`,
   442  		},
   443  	}
   444  
   445  	t.Run("write default", func(t *testing.T) {
   446  		edata := []byte(`{"Base":{"LogID":"c"},"Subfix":1,"Path":"b","InnerBase":{"Bool":true}}`)
   447  		exp := example3.NewExampleReq()
   448  		exp.InnerBase = sample.GetEmptyInnerBase3()
   449  		exp.RawUri = req.GetUri()
   450  		err = json.Unmarshal(edata, exp)
   451  		require.Nil(t, err)
   452  		cv := NewBinaryConv(conv.Options{
   453  			EnableHttpMapping:            true,
   454  			WriteDefaultField:            true,
   455  			ReadHttpValueFallback:        true,
   456  			TracebackRequredOrRootFields: true,
   457  		})
   458  		ctx := context.Background()
   459  		ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
   460  		out, err := cv.Do(ctx, desc, data)
   461  		require.NoError(t, err)
   462  		act := example3.NewExampleReq()
   463  		_, err = act.FastRead(out)
   464  		require.Nil(t, err)
   465  		require.Equal(t, exp, act)
   466  	})
   467  
   468  	t.Run("not write default", func(t *testing.T) {
   469  		edata := []byte(`{"Base":{"LogID":"c"},"Subfix":1,"Path":"b","InnerBase":{"Bool":true}}`)
   470  		exp := example3.NewExampleReq()
   471  		exp.RawUri = req.GetUri()
   472  		err = json.Unmarshal(edata, exp)
   473  		require.Nil(t, err)
   474  		cv := NewBinaryConv(conv.Options{
   475  			WriteRequireField:            true,
   476  			EnableHttpMapping:            true,
   477  			WriteDefaultField:            false,
   478  			ReadHttpValueFallback:        true,
   479  			TracebackRequredOrRootFields: true,
   480  		})
   481  		ctx := context.Background()
   482  		ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
   483  		out, err := cv.Do(ctx, desc, data)
   484  		require.NoError(t, err)
   485  		act := example3.NewExampleReq()
   486  		_, err = act.FastRead(out)
   487  		require.Nil(t, err)
   488  		require.Equal(t, exp, act)
   489  	})
   490  }
   491  
   492  func TestRequireness(t *testing.T) {
   493  	desc := getErrorExampleDesc()
   494  	data := []byte(`{}`)
   495  	cv := NewBinaryConv(conv.Options{
   496  		EnableHttpMapping: true,
   497  	})
   498  	ctx := context.Background()
   499  	req := http.NewHTTPRequest()
   500  	req.Request, _ = stdh.NewRequest("GET", "root?query=abc", bytes.NewBuffer(nil))
   501  	ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
   502  	out, err := cv.Do(ctx, desc, data)
   503  	require.Nil(t, err)
   504  	act := example3.NewExampleError()
   505  	_, err = act.FastRead(out)
   506  	require.Nil(t, err)
   507  	require.Equal(t, req.URL.Query().Get("query"), act.Query)
   508  }
   509  
   510  func TestNullJSON2Thrift(t *testing.T) {
   511  	desc := getNullDesc()
   512  	data := getNullData()
   513  	cv := NewBinaryConv(conv.Options{})
   514  	ctx := context.Background()
   515  	out, err := cv.Do(ctx, desc, data)
   516  	require.Nil(t, err)
   517  	exp := null.NewNullStruct()
   518  	err = json.Unmarshal(data, exp)
   519  	require.Nil(t, err)
   520  
   521  	var m = map[string]interface{}{}
   522  	err = json.Unmarshal(data, &m)
   523  	require.Nil(t, err)
   524  	fmt.Printf("%#v", m)
   525  
   526  	act := null.NewNullStruct()
   527  	_, err = act.FastRead(out)
   528  	require.Nil(t, err)
   529  	// require.Equal(t, exp, act)
   530  }
   531  
   532  func TestApiBody(t *testing.T) {
   533  	desc := getExampleDescByName("ApiBodyMethod", true, thrift.Options{})
   534  	data := []byte(`{"code":1024,"InnerCode":{}}`)
   535  	cv := NewBinaryConv(conv.Options{
   536  		EnableHttpMapping:            true,
   537  		WriteDefaultField:            true,
   538  		ReadHttpValueFallback:        true,
   539  		TracebackRequredOrRootFields: true,
   540  	})
   541  	ctx := context.Background()
   542  	req, err := stdh.NewRequest("POST", "http://localhost:8888/root", bytes.NewBuffer(data))
   543  	require.Nil(t, err)
   544  	req.Header.Set("Content-Type", "application/json")
   545  	r, err := http.NewHTTPRequestFromStdReq(req)
   546  	ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, r)
   547  	out, err := cv.Do(ctx, desc, data)
   548  	require.Nil(t, err)
   549  	act := example3.NewExampleApiBody()
   550  	_, err = act.FastRead(out)
   551  	require.Nil(t, err)
   552  	require.Equal(t, int64(1024), act.Code)
   553  	require.Equal(t, int16(1024), act.Code2)
   554  	require.Equal(t, int64(1024), act.InnerCode.C1)
   555  	require.Equal(t, int16(0), act.InnerCode.C2)
   556  }
   557  
   558  func TestError(t *testing.T) {
   559  	desc := getExampleDesc()
   560  
   561  	t.Run("ERR_NULL_REQUIRED", func(t *testing.T) {
   562  		desc := getNullDesc()
   563  		data := getNullErrData()
   564  		cv := NewBinaryConv(conv.Options{})
   565  		ctx := context.Background()
   566  		_, err := cv.Do(ctx, desc, data)
   567  		require.Error(t, err)
   568  		msg := err.Error()
   569  		require.Equal(t, meta.ErrMissRequiredField, err.(meta.Error).Code.Behavior())
   570  		require.True(t, strings.Contains(msg, "missing required field 3"))
   571  		cv2 := NewBinaryConv(conv.Options{
   572  			WriteRequireField: true,
   573  		})
   574  		_, err2 := cv2.Do(context.Background(), desc, data)
   575  		require.NoError(t, err2)
   576  		// require.True(t, strings.Contains(msg, "near "+strconv.Itoa(strings.Index(string(data), `"Null3": null`)+13)))
   577  	})
   578  
   579  	t.Run("INVALID_CHAR", func(t *testing.T) {
   580  		data := `{xx}`
   581  		cv := NewBinaryConv(conv.Options{})
   582  		ctx := context.Background()
   583  		_, err := cv.Do(ctx, desc, []byte(data))
   584  		require.Error(t, err)
   585  		msg := err.Error()
   586  		require.Equal(t, meta.ErrRead, err.(meta.Error).Code.Behavior())
   587  		require.True(t, strings.Contains(msg, "invalid char 'x' for state J2T_OBJ_0"))
   588  		// require.True(t, strings.Contains(msg, "near 2"))
   589  	})
   590  
   591  	t.Run("ERR_INVALID_NUMBER_FMT", func(t *testing.T) {
   592  		desc := getExampleInt2FloatDesc()
   593  		data := []byte(`{"Float64":1.x1}`)
   594  		cv := NewBinaryConv(conv.Options{
   595  			EnableValueMapping: true,
   596  		})
   597  		ctx := context.Background()
   598  		_, err := cv.Do(ctx, desc, data)
   599  		require.Error(t, err)
   600  		msg := err.Error()
   601  		require.Equal(t, meta.ErrConvert, err.(meta.Error).Code.Behavior())
   602  		require.True(t, strings.Contains(msg, "unexpected number type"))
   603  		// require.True(t, strings.Contains(msg, "near 41"))
   604  	})
   605  
   606  	t.Run("ERR_UNSUPPORT_THRIFT_TYPE", func(t *testing.T) {
   607  		desc := getErrorExampleDesc()
   608  		data := []byte(`{"MapInnerBaseInnerBase":{"a":"a"}`)
   609  		cv := NewBinaryConv(conv.Options{})
   610  		ctx := context.Background()
   611  		_, err := cv.Do(ctx, desc, data)
   612  		require.Error(t, err)
   613  		msg := err.Error()
   614  		require.Equal(t, meta.ErrUnsupportedType, err.(meta.Error).Code.Behavior())
   615  		require.True(t, strings.Contains(msg, "unsupported thrift type STRUCT"))
   616  		// require.True(t, strings.Contains(msg, "near 32"))
   617  	})
   618  
   619  	t.Run("ERR_DISMATCH_TYPE", func(t *testing.T) {
   620  		data := getExampleData()
   621  		n, err := sjson.NewSearcher(string(data)).GetByPath()
   622  		require.Nil(t, err)
   623  		exist, err := n.Set("code_code", sjson.NewString("1.1"))
   624  		require.True(t, exist)
   625  		require.Nil(t, err)
   626  		data, err = n.MarshalJSON()
   627  		require.Nil(t, err)
   628  		cv := NewBinaryConv(conv.Options{})
   629  		ctx := context.Background()
   630  		_, err = cv.Do(ctx, desc, data)
   631  		require.Error(t, err)
   632  		msg := err.Error()
   633  		require.Equal(t, meta.ErrDismatchType, err.(meta.Error).Code.Behavior())
   634  		require.True(t, strings.Contains(msg, "expect type I64 but got type 11"))
   635  	})
   636  
   637  	t.Run("ERR_UNKNOWN_FIELD", func(t *testing.T) {
   638  		desc := getErrorExampleDesc()
   639  		data := []byte(`{"UnknownField":"1"}`)
   640  		cv := NewBinaryConv(conv.Options{
   641  			DisallowUnknownField: true,
   642  		})
   643  		ctx := context.Background()
   644  		_, err := cv.Do(ctx, desc, data)
   645  		require.Error(t, err)
   646  		msg := err.Error()
   647  		require.Equal(t, meta.ErrUnknownField, err.(meta.Error).Code.Behavior())
   648  		require.True(t, strings.Contains(msg, "unknown field 'UnknownField'"))
   649  	})
   650  
   651  	t.Run("ERR_UNKNOWN_FIELD", func(t *testing.T) {
   652  		desc := getErrorExampleDesc()
   653  		data := []byte(`{"UnknownField":"1"}`)
   654  		cv := NewBinaryConv(conv.Options{
   655  			DisallowUnknownField: true,
   656  		})
   657  		ctx := context.Background()
   658  		_, err := cv.Do(ctx, desc, data)
   659  		require.Error(t, err)
   660  		msg := err.Error()
   661  		require.Equal(t, meta.ErrUnknownField, err.(meta.Error).Code.Behavior())
   662  		require.True(t, strings.Contains(msg, "unknown field 'UnknownField'"))
   663  	})
   664  
   665  	t.Run("ERR_DECODE_BASE64", func(t *testing.T) {
   666  		desc := getErrorExampleDesc()
   667  		data := []byte(`{"Base64":"xxx"}`)
   668  		cv := NewBinaryConv(conv.Options{})
   669  		ctx := context.Background()
   670  		_, err := cv.Do(ctx, desc, data)
   671  		require.Error(t, err)
   672  		msg := err.Error()
   673  		require.Equal(t, meta.ErrRead, err.(meta.Error).Code.Behavior())
   674  		require.True(t, strings.Contains(msg, "decode base64 error: "))
   675  	})
   676  
   677  	t.Run("ERR_RECURSE_EXCEED_MAX", func(t *testing.T) {
   678  		desc := getExampleInt2FloatDesc()
   679  		src := []byte(`{}`)
   680  		cv := NewBinaryConv(conv.Options{})
   681  		ctx := context.Background()
   682  		buf := make([]byte, 0, 1)
   683  		mock := MockConv{
   684  			sp:        types.MAX_RECURSE + 1,
   685  			reqsCache: 1,
   686  			keyCache:  1,
   687  			dcap:      800,
   688  		}
   689  		err := mock.do(&cv, ctx, src, desc, &buf, nil, true)
   690  		require.Error(t, err)
   691  		msg := err.Error()
   692  		require.Equal(t, meta.ErrStackOverflow, err.(meta.Error).Code.Behavior())
   693  		require.True(t, strings.Contains(msg, "stack "+strconv.Itoa(types.MAX_RECURSE+1)+" overflow"))
   694  	})
   695  }
   696  
   697  func TestFloat2Int(t *testing.T) {
   698  	t.Run("double2int", func(t *testing.T) {
   699  		desc := getExampleInt2FloatDesc()
   700  		data := []byte(`{"Int32":2.229e+2}`)
   701  		cv := NewBinaryConv(conv.Options{})
   702  		ctx := context.Background()
   703  		out, err := cv.Do(ctx, desc, data)
   704  		require.NoError(t, err)
   705  		exp := example3.NewExampleInt2Float()
   706  		_, err = exp.FastRead(out)
   707  		require.Nil(t, err)
   708  		require.Equal(t, exp.Int32, int32(222))
   709  	})
   710  	t.Run("int2double", func(t *testing.T) {
   711  		desc := getExampleInt2FloatDesc()
   712  		data := []byte(`{"Float64":` + strconv.Itoa(math.MaxInt64) + `}`)
   713  		cv := NewBinaryConv(conv.Options{})
   714  		ctx := context.Background()
   715  		out, err := cv.Do(ctx, desc, data)
   716  		require.NoError(t, err)
   717  		exp := example3.NewExampleInt2Float()
   718  		_, err = exp.FastRead(out)
   719  		require.Nil(t, err)
   720  		require.Equal(t, exp.Float64, float64(math.MaxInt64))
   721  	})
   722  }
   723  
   724  type MockConv struct {
   725  	sp        int
   726  	reqsCache int
   727  	keyCache  int
   728  	dcap      int
   729  	fc        int
   730  }
   731  
   732  func (mock *MockConv) Do(self *BinaryConv, ctx context.Context, desc *thrift.TypeDescriptor, jbytes []byte) (tbytes []byte, err error) {
   733  	buf := conv.NewBytes()
   734  
   735  	var req http.RequestGetter
   736  	if self.opts.EnableHttpMapping {
   737  		reqi := ctx.Value(conv.CtxKeyHTTPRequest)
   738  		if reqi != nil {
   739  			reqi, ok := reqi.(http.RequestGetter)
   740  			if !ok {
   741  				return nil, newError(meta.ErrInvalidParam, "invalid http.RequestGetter", nil)
   742  			}
   743  			req = reqi
   744  		} else {
   745  			return nil, newError(meta.ErrInvalidParam, "EnableHttpMapping but no http response in context", nil)
   746  		}
   747  	}
   748  
   749  	err = mock.do(self, ctx, jbytes, desc, buf, req, true)
   750  
   751  	if err == nil && len(*buf) > 0 {
   752  		tbytes = make([]byte, len(*buf))
   753  		copy(tbytes, *buf)
   754  	}
   755  
   756  	conv.FreeBytes(buf)
   757  	return
   758  }
   759  
   760  func (mock MockConv) do(self *BinaryConv, ctx context.Context, src []byte, desc *thrift.TypeDescriptor, buf *[]byte, req http.RequestGetter, top bool) (err error) {
   761  	flags := toFlags(self.opts)
   762  	jp := rt.Mem2Str(src)
   763  	tmp := make([]byte, 0, mock.dcap)
   764  	fsm := &types.J2TStateMachine{
   765  		SP: mock.sp,
   766  		JT: types.JsonState{
   767  			Dbuf: *(**byte)(unsafe.Pointer(&tmp)),
   768  			Dcap: mock.dcap,
   769  		},
   770  		ReqsCache:  make([]byte, 0, mock.reqsCache),
   771  		KeyCache:   make([]byte, 0, mock.keyCache),
   772  		SM:         types.StateMachine{},
   773  		VT:         [types.MAX_RECURSE]types.J2TState{},
   774  		FieldCache: make([]int32, 0, mock.fc),
   775  	}
   776  	fsm.Init(0, unsafe.Pointer(desc))
   777  	if mock.sp != 0 {
   778  		fsm.SP = mock.sp
   779  	}
   780  
   781  exec:
   782  	ret := native.J2T_FSM(fsm, buf, &jp, flags)
   783  	if ret != 0 {
   784  		cont, e := self.handleError(ctx, fsm, buf, src, req, ret, top)
   785  		if cont && e == nil {
   786  			goto exec
   787  		}
   788  		err = e
   789  		goto ret
   790  	}
   791  
   792  ret:
   793  	types.FreeJ2TStateMachine(fsm)
   794  	runtime.KeepAlive(desc)
   795  	return
   796  }
   797  
   798  func TestStateMachineOOM(t *testing.T) {
   799  	desc := getExampleInt2FloatDesc()
   800  	src := []byte(`{"\u4e2d\u6587":"\u4e2d\u6587", "Int32":222}`)
   801  	println(((uint8)([]byte(`中文`)[5])))
   802  	f := desc.Struct().FieldByKey("中文")
   803  	require.NotNil(t, f)
   804  	cv := NewBinaryConv(conv.Options{})
   805  	ctx := context.Background()
   806  	buf := make([]byte, 0, 1)
   807  	mock := MockConv{
   808  		sp:        0,
   809  		reqsCache: 1,
   810  		keyCache:  1,
   811  		dcap:      800,
   812  	}
   813  	err := mock.do(&cv, ctx, src, desc, &buf, nil, true)
   814  	require.Nil(t, err)
   815  	exp := example3.NewExampleInt2Float()
   816  	err = json.Unmarshal(src, exp)
   817  	require.NoError(t, err)
   818  	act := example3.NewExampleInt2Float()
   819  	_, err = act.FastRead(buf)
   820  	require.Nil(t, err)
   821  	require.Equal(t, exp, act)
   822  
   823  	t.Run("field cache OOM", func(t *testing.T) {
   824  		desc := getExampleDesc()
   825  		data := []byte(`{}`)
   826  		hr, err := stdh.NewRequest("POST", "http://localhost:8888/root?Msg=a&Subfix=1", bytes.NewBuffer(nil))
   827  		hr.Header.Set("Base", `{"LogID":"c"}`)
   828  		hr.Header.Set("Path", `b`)
   829  		// NOTICE: optional field will be ignored
   830  		hr.Header.Set("Extra", `{"x":"y"}`)
   831  		require.NoError(t, err)
   832  		req := &http.HTTPRequest{
   833  			Request: hr,
   834  			BodyMap: map[string]string{
   835  				"InnerBase": `{"Bool":true}`,
   836  			},
   837  		}
   838  		edata := []byte(`{"Base":{"LogID":"c"},"Subfix":1,"Path":"b","InnerBase":{"Bool":true}}`)
   839  		exp := example3.NewExampleReq()
   840  		exp.RawUri = req.GetUri()
   841  		err = json.Unmarshal(edata, exp)
   842  		require.Nil(t, err)
   843  		exp.RawUri = req.GetUri()
   844  		mock := MockConv{
   845  			sp:        1,
   846  			reqsCache: 1,
   847  			keyCache:  1,
   848  			dcap:      800,
   849  			fc:        0,
   850  		}
   851  		cv := NewBinaryConv(conv.Options{
   852  			EnableHttpMapping:            true,
   853  			WriteRequireField:            true,
   854  			ReadHttpValueFallback:        true,
   855  			TracebackRequredOrRootFields: true,
   856  		})
   857  		ctx := context.Background()
   858  		ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
   859  		out, err := mock.Do(&cv, ctx, desc, data)
   860  		require.NoError(t, err)
   861  		act := example3.NewExampleReq()
   862  		_, err = act.FastRead(out)
   863  		require.Nil(t, err)
   864  		require.Equal(t, exp, act)
   865  	})
   866  }
   867  
   868  func TestEmptyConvHTTP2Thrift(t *testing.T) {
   869  	desc := getExampleDesc()
   870  	data := []byte(``)
   871  	exp := example3.NewExampleReq()
   872  	req := getExampleReq(exp, false, data)
   873  	cv := NewBinaryConv(conv.Options{
   874  		EnableHttpMapping: true,
   875  	})
   876  	ctx := context.Background()
   877  	ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
   878  	out, err := cv.Do(ctx, desc, data)
   879  	require.NoError(t, err)
   880  
   881  	act := example3.NewExampleReq()
   882  	_, err = act.FastRead(out)
   883  	require.Nil(t, err)
   884  	require.Equal(t, exp, act)
   885  }
   886  
   887  func TestThriftRequestBase(t *testing.T) {
   888  	desc := getExampleDescByName("ExampleMethod", true, thrift.Options{
   889  		// NOTICE: must set options.EnableThriftBase to true
   890  		EnableThriftBase: true,
   891  	})
   892  	cv := NewBinaryConv(conv.Options{
   893  		EnableThriftBase:  true,
   894  		WriteDefaultField: true,
   895  	})
   896  	ctx := context.Background()
   897  	b := base.NewBase()
   898  	b.Caller = "caller"
   899  	b.Extra = map[string]string{
   900  		"key": "value",
   901  	}
   902  	b.TrafficEnv = &base.TrafficEnv{
   903  		Env: "env",
   904  	}
   905  	ctx = context.WithValue(ctx, conv.CtxKeyThriftReqBase, b)
   906  	app, err := json.Marshal(b)
   907  	require.NoError(t, err)
   908  	data := getExampleData()
   909  
   910  	t.Run("context base", func(t *testing.T) {
   911  		root, _ := sjson.NewSearcher(string(data)).GetByPath()
   912  		_, err := root.Unset("Base")
   913  		require.NoError(t, err)
   914  		str, _ := root.Raw()
   915  		in := []byte(str)
   916  		out, err := cv.Do(ctx, desc, in)
   917  		require.NoError(t, err)
   918  		act := example3.NewExampleReq()
   919  		_, err = act.FastRead(out)
   920  
   921  		exp := example3.NewExampleReq()
   922  		_, err = root.Set("Base", sjson.NewRaw(string(app)))
   923  		require.NoError(t, err)
   924  		str, _ = root.Raw()
   925  		err = json.Unmarshal([]byte(str), exp)
   926  		require.Nil(t, err)
   927  		require.Equal(t, exp, act)
   928  	})
   929  
   930  	// NOTICE: when both body and context base are set, body base will be used
   931  	t.Run("ctx + json base", func(t *testing.T) {
   932  		out, err := cv.Do(ctx, desc, data)
   933  		require.NoError(t, err)
   934  		act := example3.NewExampleReq()
   935  		_, err = act.FastRead(out)
   936  		exp := example3.NewExampleReq()
   937  		err = json.Unmarshal(data, exp)
   938  		require.Nil(t, err)
   939  		require.Equal(t, exp, act)
   940  	})
   941  }
   942  
   943  func TestString2Int(t *testing.T) {
   944  	desc := getExampleInt2FloatDesc()
   945  	cv := NewBinaryConv(conv.Options{
   946  		String2Int64: true,
   947  	})
   948  	t.Run("converting", func(t *testing.T) {
   949  		data := []byte(`{"Int32":"", "Float64":"1.1", "中文": 123.3}`)
   950  		cv.SetOptions(conv.Options{
   951  			EnableValueMapping: true,
   952  		})
   953  		ctx := context.Background()
   954  		out, err := cv.Do(ctx, desc, data)
   955  		require.Nil(t, err)
   956  		exp := example3.NewExampleInt2Float()
   957  		exp.Int32 = 0
   958  		exp.Float64 = 1.1
   959  		exp.String_ = "123.3"
   960  		act := example3.NewExampleInt2Float()
   961  		_, err = act.FastRead(out)
   962  		require.Nil(t, err)
   963  		require.Equal(t, exp, act)
   964  	})
   965  
   966  	t.Run("no-converting", func(t *testing.T) {
   967  		data := []byte(`{"Int32":222, "Float64":1.1, "中文": "123.3"}`)
   968  		cv.SetOptions(conv.Options{
   969  			EnableValueMapping: true,
   970  		})
   971  		ctx := context.Background()
   972  		out, err := cv.Do(ctx, desc, data)
   973  		require.Nil(t, err)
   974  		exp := example3.NewExampleInt2Float()
   975  		exp.Int32 = 222
   976  		exp.Float64 = 1.1
   977  		exp.String_ = "123.3"
   978  		act := example3.NewExampleInt2Float()
   979  		_, err = act.FastRead(out)
   980  		require.Nil(t, err)
   981  		require.Equal(t, exp, act)
   982  	})
   983  
   984  	t.Run("option Int64AsString", func(t *testing.T) {
   985  		data := []byte(`{"Int32":"222","Int64":"333", "Float64":"1.1"}`)
   986  		cv.SetOptions(conv.Options{
   987  			String2Int64: true,
   988  		})
   989  		ctx := context.Background()
   990  		out, err := cv.Do(ctx, desc, data)
   991  		require.Nil(t, err)
   992  		exp := example3.NewExampleInt2Float()
   993  		exp.Int64 = 333
   994  		exp.Int32 = 222
   995  		exp.Float64 = 1.1
   996  		act := example3.NewExampleInt2Float()
   997  		_, err = act.FastRead(out)
   998  		require.Nil(t, err)
   999  		require.Equal(t, exp, act)
  1000  	})
  1001  }
  1002  
  1003  func TestJSONString(t *testing.T) {
  1004  	desc := getExampleJSONStringDesc()
  1005  	data := []byte(``)
  1006  	exp := example3.NewExampleJSONString()
  1007  	req := getExampleJSONStringReq(exp)
  1008  	cv := NewBinaryConv(conv.Options{
  1009  		EnableHttpMapping: true,
  1010  	})
  1011  	ctx := context.Background()
  1012  	ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
  1013  	out, err := cv.Do(ctx, desc, data)
  1014  	require.NoError(t, err)
  1015  
  1016  	act := example3.NewExampleJSONString()
  1017  	_, err = act.FastRead(out)
  1018  	require.Nil(t, err)
  1019  	require.Equal(t, exp, act)
  1020  }
  1021  
  1022  func TestHttpConvError(t *testing.T) {
  1023  	desc := getErrorExampleDesc()
  1024  	t.Run("nil required", func(t *testing.T) {
  1025  		data := []byte(`{}`)
  1026  		hr, err := stdh.NewRequest("GET", "http://localhost", nil)
  1027  		require.Nil(t, err)
  1028  		req := &http.HTTPRequest{
  1029  			Request: hr,
  1030  		}
  1031  		cv := NewBinaryConv(conv.Options{
  1032  			EnableHttpMapping: true,
  1033  		})
  1034  		ctx := context.Background()
  1035  		ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
  1036  		_, err = cv.Do(ctx, desc, data)
  1037  		require.Error(t, err)
  1038  		require.Equal(t, meta.ErrMissRequiredField, err.(meta.Error).Code.Behavior())
  1039  	})
  1040  
  1041  	t.Run("write default", func(t *testing.T) {
  1042  		data := []byte(`{}`)
  1043  		hr, err := stdh.NewRequest("GET", "http://localhost?query=a", nil)
  1044  		require.Nil(t, err)
  1045  		hr.Header = stdh.Header{}
  1046  		req := &http.HTTPRequest{
  1047  			Request: hr,
  1048  		}
  1049  		cv := NewBinaryConv(conv.Options{
  1050  			EnableHttpMapping: true,
  1051  			WriteDefaultField: true,
  1052  		})
  1053  		ctx := context.Background()
  1054  		ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
  1055  		out, err := cv.Do(ctx, desc, data)
  1056  		require.NoError(t, err)
  1057  		var exp = example3.NewExampleError()
  1058  		_, err = exp.FastRead(out)
  1059  		require.Nil(t, err)
  1060  		require.Equal(t, "a", exp.Query)
  1061  		require.Equal(t, "", exp.Header)
  1062  	})
  1063  
  1064  	t.Run("dismathed type", func(t *testing.T) {
  1065  		data := []byte(`{}`)
  1066  		hr, err := stdh.NewRequest("GET", "http://localhost?query=a&q2=1.5", nil)
  1067  		require.Nil(t, err)
  1068  		req := &http.HTTPRequest{
  1069  			Request: hr,
  1070  		}
  1071  		cv := NewBinaryConv(conv.Options{
  1072  			EnableHttpMapping: true,
  1073  		})
  1074  		ctx := context.Background()
  1075  		ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
  1076  		_, err = cv.Do(ctx, desc, data)
  1077  		require.Error(t, err)
  1078  		require.Equal(t, meta.ErrConvert, err.(meta.Error).Code.Behavior())
  1079  	})
  1080  }
  1081  
  1082  func TestHttpMappingFallback(t *testing.T) {
  1083  	desc := getExampleFallbackDesc()
  1084  	data := []byte(`{"Msg":"hello","Heeader":"world"}`)
  1085  	t.Run("fallback", func(t *testing.T) {
  1086  		hr, err := stdh.NewRequest("GET", "http://localhost?query=a", nil)
  1087  		req := &http.HTTPRequest{
  1088  			Request: hr,
  1089  		}
  1090  		cv := NewBinaryConv(conv.Options{
  1091  			EnableHttpMapping:     true,
  1092  			ReadHttpValueFallback: true,
  1093  		})
  1094  		ctx := context.Background()
  1095  		ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
  1096  		out, err := cv.Do(ctx, desc, data)
  1097  		require.NoError(t, err)
  1098  		exp := example3.NewExampleFallback()
  1099  		exp.Msg = "hello"
  1100  		exp.Heeader = "world"
  1101  		act := example3.NewExampleFallback()
  1102  		_, err = act.FastRead(out)
  1103  		require.Nil(t, err)
  1104  		require.Equal(t, exp, act)
  1105  	})
  1106  	t.Run("not fallback", func(t *testing.T) {
  1107  		hr, err := stdh.NewRequest("GET", "http://localhost?A=a", nil)
  1108  		hr.Header.Set("heeader", "中文")
  1109  		req := &http.HTTPRequest{
  1110  			Request: hr,
  1111  		}
  1112  		cv := NewBinaryConv(conv.Options{
  1113  			EnableHttpMapping: true,
  1114  		})
  1115  		ctx := context.Background()
  1116  		ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
  1117  		out, err := cv.Do(ctx, desc, data)
  1118  		require.NoError(t, err)
  1119  		exp := example3.NewExampleFallback()
  1120  		exp.Msg = "a"
  1121  		exp.Heeader = "中文"
  1122  		act := example3.NewExampleFallback()
  1123  		_, err = act.FastRead(out)
  1124  		require.Nil(t, err)
  1125  		require.Equal(t, exp, act)
  1126  	})
  1127  }
  1128  
  1129  func TestPostFormBody(t *testing.T) {
  1130  	desc := getExampleDescByName("PostFormMethod", true, thrift.Options{})
  1131  	data := url.Values{
  1132  		"form":       []string{"b"},
  1133  		"JSON":       []string{`{"a":"中文","b":1}`},
  1134  		"inner_form": []string{"1"},
  1135  	}
  1136  	t.Run("fallback", func(t *testing.T) {
  1137  		exp := example3.NewExamplePostForm()
  1138  		exp.Query = "a"
  1139  		exp.Form = "b"
  1140  		exp.JSON = &example3.InnerJSON{
  1141  			A:         "中文",
  1142  			B:         1,
  1143  			InnerForm: 0,
  1144  		}
  1145  		cv := NewBinaryConv(conv.Options{
  1146  			WriteDefaultField:            true,
  1147  			EnableHttpMapping:            true,
  1148  			ReadHttpValueFallback:        true,
  1149  			TracebackRequredOrRootFields: true,
  1150  		})
  1151  		ctx := context.Background()
  1152  		sr, err := stdh.NewRequest("POST", "http://localhost?query=a", strings.NewReader(data.Encode()))
  1153  		require.NoError(t, err)
  1154  		sr.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  1155  		req, err := http.NewHTTPRequestFromStdReq(sr)
  1156  		require.NoError(t, err)
  1157  		ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
  1158  		out, err := cv.Do(ctx, desc, []byte(`{}`))
  1159  		require.Nil(t, err)
  1160  		act := example3.NewExamplePostForm()
  1161  		_, err = act.FastRead(out)
  1162  		require.Nil(t, err)
  1163  		require.Equal(t, exp, act)
  1164  	})
  1165  	t.Run("no fallback", func(t *testing.T) {
  1166  		exp := example3.NewExamplePostForm()
  1167  		exp.Query = "a"
  1168  		exp.Form = "b"
  1169  		// exp.JSON = &example3.InnerJSON{
  1170  		// 	A: "中文",
  1171  		// 	B: 1,
  1172  		// 	InnerForm: 1,
  1173  		// }   //NOTICE: not set since conv data is nil, thus no fallback
  1174  		cv := NewBinaryConv(conv.Options{
  1175  			WriteDefaultField: false,
  1176  			EnableHttpMapping: true,
  1177  		})
  1178  		ctx := context.Background()
  1179  		sr, err := stdh.NewRequest("POST", "http://localhost?query=a", strings.NewReader(data.Encode()))
  1180  		require.NoError(t, err)
  1181  		sr.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  1182  		req, err := http.NewHTTPRequestFromStdReq(sr)
  1183  		require.NoError(t, err)
  1184  		ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
  1185  		out, err := cv.Do(ctx, desc, []byte(``))
  1186  		require.Nil(t, err)
  1187  		act := example3.NewExamplePostForm()
  1188  		_, err = act.FastRead(out)
  1189  		require.Nil(t, err)
  1190  		require.Equal(t, exp, act)
  1191  	})
  1192  }
  1193  
  1194  func TestAGWDynamicBody(t *testing.T) {
  1195  	desc := getExampleDescByName("DynamicStructMethod", true, thrift.Options{})
  1196  	exp := example3.NewExampleDynamicStruct()
  1197  	exp.Query = "1"
  1198  	exp.JSON = "[1,2,3]"
  1199  	exp.InnerStruct = &example3.InnerStruct{
  1200  		InnerJSON: `{"a":"中文","b":1}`,
  1201  		Must:      "2",
  1202  	}
  1203  	t.Run("no http-mapping", func(t *testing.T) {
  1204  		data := `{"Query":"1","json":[1,2,3],"inner_struct":{"inner_json":{"a":"中文","b":1},"Must":"2"}}`
  1205  		cv := NewBinaryConv(conv.Options{
  1206  			EnableValueMapping:    true,
  1207  			EnableHttpMapping:     false,
  1208  			WriteRequireField:     true,
  1209  			ReadHttpValueFallback: true,
  1210  		})
  1211  		ctx := context.Background()
  1212  		out, err := cv.Do(ctx, desc, []byte(data))
  1213  		require.Nil(t, err)
  1214  		act := example3.NewExampleDynamicStruct()
  1215  		_, err = act.FastRead(out)
  1216  		require.Nil(t, err)
  1217  		require.Equal(t, exp, act)
  1218  	})
  1219  	t.Run("http-mapping", func(t *testing.T) {
  1220  		data := `{"json":[1,2,3],"inner_struct":{"inner_json":{"a":"中文","b":1}}}`
  1221  		cv := NewBinaryConv(conv.Options{
  1222  			EnableValueMapping:           true,
  1223  			EnableHttpMapping:            true,
  1224  			WriteRequireField:            true,
  1225  			ReadHttpValueFallback:        true,
  1226  			TracebackRequredOrRootFields: true,
  1227  		})
  1228  		ctx := context.Background()
  1229  		req, err := stdh.NewRequest("GET", "http://localhost?query=1&Must=2", nil)
  1230  		require.NoError(t, err)
  1231  		rr, err := http.NewHTTPRequestFromStdReq(req)
  1232  		require.NoError(t, err)
  1233  		ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, rr)
  1234  		out, err := cv.Do(ctx, desc, []byte(data))
  1235  		require.Nil(t, err)
  1236  		act := example3.NewExampleDynamicStruct()
  1237  		_, err = act.FastRead(out)
  1238  		require.Nil(t, err)
  1239  		require.Equal(t, exp, act)
  1240  	})
  1241  }
  1242  
  1243  func TestNobodyRequiredFields(t *testing.T) {
  1244  	path := "a/b/main.thrift"
  1245  	content := `
  1246  	namespace go kitex.test.server
  1247  	struct Base {
  1248  		1: required string required_field
  1249  	}
  1250  
  1251  	service InboxService {
  1252  		string ExampleMethod(1: Base req)
  1253  	}
  1254  	`
  1255  	includes := map[string]string{
  1256  		path: content,
  1257  	}
  1258  	p, err := thrift.NewDescritorFromContent(context.Background(), path, content, includes, true)
  1259  	if err != nil {
  1260  		t.Fatal(err)
  1261  	}
  1262  	desc := p.Functions()["ExampleMethod"].Request().Struct().Fields()[0].Type()
  1263  	cv := NewBinaryConv(conv.Options{
  1264  		EnableHttpMapping:     true,
  1265  		WriteRequireField:     true,
  1266  		ReadHttpValueFallback: true,
  1267  	})
  1268  	ctx := context.Background()
  1269  	req, err := http.NewHTTPRequestFromUrl("GET", "http://localhost?required_field=1", nil)
  1270  	require.NoError(t, err)
  1271  	ctx = context.WithValue(ctx, conv.CtxKeyHTTPRequest, req)
  1272  	out, err := cv.Do(ctx, desc, nil)
  1273  	require.Nil(t, err)
  1274  	fmt.Printf("%+v", out)
  1275  }
  1276  
  1277  func TestBase64Decode(t *testing.T) {
  1278  	desc := getExampleDescByName("Base64BinaryMethod", true, thrift.Options{})
  1279  	t.Run("base64 decode", func(t *testing.T) {
  1280  		exp := example3.NewExampleBase64Binary()
  1281  		exp.Binary = []byte("hello")
  1282  		in, err := json.Marshal(exp)
  1283  		require.Nil(t, err)
  1284  		cv := NewBinaryConv(conv.Options{
  1285  			EnableHttpMapping: true,
  1286  			NoBase64Binary:    false,
  1287  		})
  1288  		req, err := http.NewHTTPRequestFromUrl("GET", "http://localhost", nil)
  1289  		require.NoError(t, err)
  1290  		req.Request.Header.Set("Binary2", base64.StdEncoding.EncodeToString([]byte("world")))
  1291  		ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPRequest, req)
  1292  		out, err := cv.Do(ctx, desc, in)
  1293  		require.Nil(t, err)
  1294  
  1295  		act := example3.NewExampleBase64Binary()
  1296  		_, err = act.FastRead(out)
  1297  		require.Nil(t, err)
  1298  		require.Equal(t, []byte("hello"), act.Binary)
  1299  		require.Equal(t, []byte("world"), act.Binary2)
  1300  	})
  1301  
  1302  	t.Run("no base64 decode", func(t *testing.T) {
  1303  		in := []byte(`{"Binary":"hello"}`)
  1304  		cv := NewBinaryConv(conv.Options{
  1305  			EnableHttpMapping: true,
  1306  			NoBase64Binary:    true,
  1307  		})
  1308  		req, err := http.NewHTTPRequestFromUrl("GET", "http://localhost", nil)
  1309  		require.NoError(t, err)
  1310  		req.Request.Header.Set("Binary2", "world")
  1311  		ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPRequest, req)
  1312  		out, err := cv.Do(ctx, desc, in)
  1313  		require.Nil(t, err)
  1314  
  1315  		act := example3.NewExampleBase64Binary()
  1316  		_, err = act.FastRead(out)
  1317  		require.Nil(t, err)
  1318  		require.Equal(t, []byte("hello"), act.Binary)
  1319  		require.Equal(t, []byte("world"), act.Binary2)
  1320  	})
  1321  }
  1322  
  1323  func TestDefaultValue(t *testing.T) {
  1324  	desc := getExampleDescByName("DefaultValueMethod", true, thrift.Options{
  1325  		UseDefaultValue: true,
  1326  	})
  1327  	in := []byte(`{}`)
  1328  	t.Run("default value", func(t *testing.T) {
  1329  		cv := NewBinaryConv(conv.Options{
  1330  			WriteDefaultField: true,
  1331  			EnableHttpMapping: false,
  1332  		})
  1333  		out, err := cv.Do(context.Background(), desc, in)
  1334  		require.Nil(t, err)
  1335  		act := &example3.ExampleDefaultValue{}
  1336  		_, err = act.FastRead(out)
  1337  		require.Nil(t, err)
  1338  		exp := example3.NewExampleDefaultValue()
  1339  		require.Equal(t, exp, act)
  1340  	})
  1341  	t.Run("default value + http mapping", func(t *testing.T) {
  1342  		cv := NewBinaryConv(conv.Options{
  1343  			WriteDefaultField: true,
  1344  			EnableHttpMapping: true,
  1345  		})
  1346  		req, err := http.NewHTTPRequestFromUrl("GET", "http://localhost", nil)
  1347  		require.NoError(t, err)
  1348  		ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPRequest, req)
  1349  		out, err := cv.Do(ctx, desc, in)
  1350  		require.Nil(t, err)
  1351  		act := &example3.ExampleDefaultValue{}
  1352  		_, err = act.FastRead(out)
  1353  		require.Nil(t, err)
  1354  
  1355  		exp := example3.NewExampleDefaultValue()
  1356  		require.Equal(t, exp, act)
  1357  	})
  1358  	t.Run("zero value", func(t *testing.T) {
  1359  		desc := getExampleDescByName("DefaultValueMethod", true, thrift.Options{
  1360  			UseDefaultValue: false,
  1361  		})
  1362  		cv := NewBinaryConv(conv.Options{
  1363  			WriteDefaultField: true,
  1364  			EnableHttpMapping: false,
  1365  		})
  1366  		req, err := http.NewHTTPRequestFromUrl("GET", "http://localhost", nil)
  1367  		require.NoError(t, err)
  1368  		ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPRequest, req)
  1369  		out, err := cv.Do(ctx, desc, in)
  1370  		require.Nil(t, err)
  1371  		act := &example3.ExampleDefaultValue{}
  1372  		_, err = act.FastRead(out)
  1373  		require.Nil(t, err)
  1374  
  1375  		exp := &example3.ExampleDefaultValue{}
  1376  		require.Equal(t, exp, act)
  1377  	})
  1378  }
  1379  
  1380  func TestOptionalDefaultValue(t *testing.T) {
  1381  	desc := getExampleDescByName("OptionalDefaultValueMethod", true, thrift.Options{
  1382  		SetOptionalBitmap: true,
  1383  		UseDefaultValue:   true,
  1384  	})
  1385  	in := []byte(`{}`)
  1386  	t.Run("write default + write optional", func(t *testing.T) {
  1387  		cv := NewBinaryConv(conv.Options{
  1388  			WriteRequireField:  true,
  1389  			WriteDefaultField:  true,
  1390  			EnableHttpMapping:  false,
  1391  			WriteOptionalField: true,
  1392  		})
  1393  		out, err := cv.Do(context.Background(), desc, in)
  1394  		require.Nil(t, err)
  1395  		act := &example3.ExampleOptionalDefaultValue{}
  1396  		_, err = act.FastRead(out)
  1397  		require.Nil(t, err)
  1398  		exp := example3.NewExampleOptionalDefaultValue()
  1399  		exp.E = new(string)
  1400  		exp.F = new(string)
  1401  		require.Equal(t, exp, act)
  1402  	})
  1403  	t.Run("not write optional", func(t *testing.T) {
  1404  		cv := NewBinaryConv(conv.Options{
  1405  			WriteRequireField: true,
  1406  			WriteDefaultField: false,
  1407  			EnableHttpMapping: false,
  1408  		})
  1409  		out, err := cv.Do(context.Background(), desc, in)
  1410  		require.Nil(t, err)
  1411  		act := &example3.ExampleOptionalDefaultValue{}
  1412  		_, err = act.FastRead(out)
  1413  		require.Nil(t, err)
  1414  		exp := example3.NewExampleOptionalDefaultValue()
  1415  		exp.A = ""
  1416  		exp.C = 0
  1417  		require.Equal(t, exp, act)
  1418  	})
  1419  	t.Run("write default", func(t *testing.T) {
  1420  		cv := NewBinaryConv(conv.Options{
  1421  			WriteRequireField: false,
  1422  			WriteDefaultField: true,
  1423  			EnableHttpMapping: false,
  1424  		})
  1425  		_, err := cv.Do(context.Background(), desc, in)
  1426  		require.Error(t, err)
  1427  	})
  1428  	t.Run("write default + http mapping", func(t *testing.T) {
  1429  		in := []byte(`{"B":1}`)
  1430  		cv := NewBinaryConv(conv.Options{
  1431  			WriteRequireField: false,
  1432  			WriteDefaultField: true,
  1433  			EnableHttpMapping: true,
  1434  		})
  1435  		req, err := http.NewHTTPRequestFromUrl("GET", "http://localhost", nil)
  1436  		require.NoError(t, err)
  1437  		ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPRequest, req)
  1438  		_, err = cv.Do(ctx, desc, in)
  1439  		require.Error(t, err)
  1440  	})
  1441  	t.Run("write default + write optional + http mapping", func(t *testing.T) {
  1442  		cv := NewBinaryConv(conv.Options{
  1443  			WriteRequireField:  true,
  1444  			WriteDefaultField:  true,
  1445  			EnableHttpMapping:  true,
  1446  			WriteOptionalField: true,
  1447  		})
  1448  		req, err := http.NewHTTPRequestFromUrl("GET", "http://localhost", nil)
  1449  		require.NoError(t, err)
  1450  		ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPRequest, req)
  1451  		out, err := cv.Do(ctx, desc, in)
  1452  		require.Nil(t, err)
  1453  		act := &example3.ExampleOptionalDefaultValue{}
  1454  		_, err = act.FastRead(out)
  1455  		require.Nil(t, err)
  1456  		exp := example3.NewExampleOptionalDefaultValue()
  1457  		exp.E = new(string)
  1458  		exp.F = new(string)
  1459  		require.Equal(t, exp, act)
  1460  	})
  1461  }
  1462  
  1463  func TestNoBodyStruct(t *testing.T) {
  1464  	desc := getExampleDescByName("NoBodyStructMethod", true, thrift.Options{
  1465  		UseDefaultValue: true,
  1466  	})
  1467  	in := []byte(`{}`)
  1468  	req, err := http.NewHTTPRequestFromUrl("GET", "http://localhost?b=1", nil)
  1469  	require.NoError(t, err)
  1470  	cv := NewBinaryConv(conv.Options{
  1471  		EnableHttpMapping: true,
  1472  	})
  1473  	ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPRequest, req)
  1474  	out, err := cv.Do(ctx, desc, in)
  1475  	require.Nil(t, err)
  1476  	act := &example3.ExampleNoBodyStruct{}
  1477  	_, err = act.FastRead(out)
  1478  	require.Nil(t, err)
  1479  	exp := example3.NewExampleNoBodyStruct()
  1480  	exp.NoBodyStruct = example3.NewNoBodyStruct()
  1481  	B := int32(1)
  1482  	exp.NoBodyStruct.B = &B
  1483  	require.Equal(t, exp, act)
  1484  }
  1485  
  1486  func TestSimpleArgs(t *testing.T) {
  1487  	cv := NewBinaryConv(conv.Options{})
  1488  
  1489  	t.Run("string", func(t *testing.T) {
  1490  		desc := getExampleDescByName("String", true, thrift.Options{})
  1491  		p := thrift.NewBinaryProtocolBuffer()
  1492  		p.WriteString("hello")
  1493  		exp := p.Buf
  1494  		out, err := cv.Do(context.Background(), desc, []byte(`"hello"`))
  1495  		require.NoError(t, err)
  1496  		require.Equal(t, exp, out)
  1497  	})
  1498  
  1499  	t.Run("no quoted string", func(t *testing.T) {
  1500  		desc := getExampleDescByName("String", true, thrift.Options{})
  1501  		p := thrift.NewBinaryProtocolBuffer()
  1502  		p.WriteString(`hel\lo`)
  1503  		exp := p.Buf
  1504  		out, err := cv.Do(context.Background(), desc, []byte(`hel\lo`))
  1505  		require.NoError(t, err)
  1506  		require.Equal(t, exp, out)
  1507  	})
  1508  
  1509  	t.Run("int", func(t *testing.T) {
  1510  		desc := getExampleDescByName("I64", true, thrift.Options{})
  1511  		p := thrift.NewBinaryProtocolBuffer()
  1512  		p.WriteI64(math.MaxInt64)
  1513  		exp := p.Buf
  1514  		out, err := cv.Do(context.Background(), desc, []byte(strconv.Itoa(math.MaxInt64)))
  1515  		require.NoError(t, err)
  1516  		require.Equal(t, exp, out)
  1517  	})
  1518  }