github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/conv/t2j/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 t2j
    18  
    19  import (
    20  	"context"
    21  	"encoding/base64"
    22  	"encoding/json"
    23  	"io/ioutil"
    24  	"math"
    25  	"os"
    26  	"reflect"
    27  	"runtime"
    28  	"runtime/debug"
    29  	"strconv"
    30  	"testing"
    31  	"time"
    32  	"unsafe"
    33  
    34  	sjson "github.com/bytedance/sonic/ast"
    35  	"github.com/cloudwego/dynamicgo/conv"
    36  	"github.com/cloudwego/dynamicgo/http"
    37  	"github.com/cloudwego/dynamicgo/internal/util_test"
    38  	"github.com/cloudwego/dynamicgo/meta"
    39  	kbase "github.com/cloudwego/dynamicgo/testdata/kitex_gen/base"
    40  	"github.com/cloudwego/dynamicgo/testdata/kitex_gen/example3"
    41  	"github.com/cloudwego/dynamicgo/thrift"
    42  	"github.com/cloudwego/dynamicgo/thrift/annotation"
    43  	"github.com/cloudwego/dynamicgo/thrift/base"
    44  	"github.com/davecgh/go-spew/spew"
    45  	"github.com/stretchr/testify/assert"
    46  	"github.com/stretchr/testify/require"
    47  )
    48  
    49  var (
    50  	debugAsyncGC = os.Getenv("SONIC_NO_ASYNC_GC") == ""
    51  )
    52  
    53  func TestMain(m *testing.M) {
    54  	go func() {
    55  		if !debugAsyncGC {
    56  			return
    57  		}
    58  		println("Begin GC looping...")
    59  		for {
    60  			runtime.GC()
    61  			debug.FreeOSMemory()
    62  		}
    63  	}()
    64  	time.Sleep(time.Millisecond)
    65  	annotation.InitAGWAnnos()
    66  	m.Run()
    67  }
    68  
    69  func GetDescByName(method string, isReq bool) *thrift.TypeDescriptor {
    70  	opts := thrift.Options{}
    71  	svc, err := opts.NewDescritorFromPath(context.Background(), util_test.MustGitPath("testdata/idl/example3.thrift"))
    72  	if err != nil {
    73  		panic(err)
    74  	}
    75  	if isReq {
    76  		return svc.Functions()[method].Request().Struct().Fields()[0].Type()
    77  	} else {
    78  		return svc.Functions()[method].Response().Struct().Fields()[0].Type()
    79  	}
    80  }
    81  
    82  func getExamplePartialDesc() *thrift.TypeDescriptor {
    83  	svc, err := thrift.NewDescritorFromPath(context.Background(), util_test.MustGitPath("testdata/idl/example3.thrift"))
    84  	if err != nil {
    85  		panic(err)
    86  	}
    87  	return svc.Functions()["PartialMethod"].Response().Struct().Fields()[0].Type()
    88  }
    89  
    90  func getExampleInt2Float() *thrift.TypeDescriptor {
    91  	svc, err := thrift.NewDescritorFromPath(context.Background(), util_test.MustGitPath("testdata/idl/example3.thrift"))
    92  	if err != nil {
    93  		panic(err)
    94  	}
    95  	return svc.Functions()["Int2FloatMethod"].Response().Struct().Fields()[0].Type()
    96  }
    97  
    98  func getExamplePartialDesc2() *thrift.TypeDescriptor {
    99  	svc, err := thrift.NewDescritorFromPath(context.Background(), util_test.MustGitPath("testdata/idl/example3.thrift"))
   100  	if err != nil {
   101  		panic(err)
   102  	}
   103  	return svc.Functions()["PartialMethod"].Request().Struct().Fields()[0].Type()
   104  }
   105  
   106  func getExampleErrorDesc() *thrift.TypeDescriptor {
   107  	svc, err := thrift.NewDescritorFromPath(context.Background(), util_test.MustGitPath("testdata/idl/example3.thrift"))
   108  	if err != nil {
   109  		panic(err)
   110  	}
   111  	return svc.Functions()["ErrorMethod"].Response().Struct().Fields()[0].Type()
   112  }
   113  
   114  func getExampleFallbackDesc() *thrift.TypeDescriptor {
   115  	svc, err := thrift.NewDescritorFromPath(context.Background(), util_test.MustGitPath("testdata/idl/example3.thrift"))
   116  	if err != nil {
   117  		panic(err)
   118  	}
   119  	return svc.Functions()["FallbackMethod"].Response().Struct().Fields()[0].Type()
   120  }
   121  
   122  func getExample3Data() []byte {
   123  	out, err := ioutil.ReadFile(util_test.MustGitPath("testdata/data/example3resp.bin"))
   124  	if err != nil {
   125  		panic(err)
   126  	}
   127  	return out
   128  }
   129  
   130  func getExmaple3JSON() string {
   131  	out, err := ioutil.ReadFile(util_test.MustGitPath("testdata/data/example3resp.json"))
   132  	if err != nil {
   133  		panic(err)
   134  	}
   135  	return string(out)
   136  }
   137  
   138  func TestConvThrift2JSON(t *testing.T) {
   139  	desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "ExampleMethod", thrift.Options{}))
   140  	// js := getExmaple3JSON()
   141  	cv := NewBinaryConv(conv.Options{})
   142  	in := getExample3Data()
   143  	out, err := cv.Do(context.Background(), desc, in)
   144  	if err != nil {
   145  		t.Fatal(err)
   146  	}
   147  	var exp, act example3.ExampleResp
   148  	// require.Nil(t, json.Unmarshal([]byte(js), &exp))
   149  	_, err = exp.FastRead(in)
   150  	require.Nil(t, err)
   151  	require.Nil(t, json.Unmarshal([]byte(out), &act))
   152  	println(string(out))
   153  	assert.Equal(t, exp, act)
   154  	// assert.Equal(t, len(js), len(out))
   155  }
   156  
   157  // func getHTTPResponse() *http.HTTPResponse {
   158  // 	return &http.HTTPResponse{
   159  // 		StatusCode: 200,
   160  // 		Header:     map[string][]string{},
   161  // 		Cookies:    map[string]*stdh.Cookie{},
   162  // 		RawBody:    []byte{},
   163  // 	}
   164  // }
   165  
   166  func chechHelper(t *testing.T, exp string, act string, opts testOptions) {
   167  	var expMap, actMap map[string]interface{}
   168  	require.Nil(t, json.Unmarshal([]byte(exp), &expMap))
   169  	require.Nil(t, json.Unmarshal([]byte(act), &actMap))
   170  	assert.True(t, checkAInB(t, reflect.ValueOf(actMap), reflect.ValueOf(expMap), opts))
   171  }
   172  
   173  type testOptions struct {
   174  	JSConv bool
   175  }
   176  
   177  func checkAInB(t *testing.T, a reflect.Value, b reflect.Value, opts testOptions) bool {
   178  	if a.IsZero() {
   179  		return true
   180  	}
   181  	if a.Kind() == reflect.Ptr || a.Kind() == reflect.Interface {
   182  		a = a.Elem()
   183  	}
   184  	if b.Kind() == reflect.Ptr || b.Kind() == reflect.Interface {
   185  		b = b.Elem()
   186  	}
   187  	// if a.Type() != b.Type() {
   188  	// 	t.Logf("type mismatch: %v != %v", a.Type(), b.Type())
   189  	// 	return false
   190  	// }
   191  	if a.Kind() != reflect.Map && a.Kind() != reflect.Slice {
   192  		if !reflect.DeepEqual(a.Interface(), b.Interface()) {
   193  			// a := a.Elem()
   194  			// b := b.Elem()
   195  			if opts.JSConv {
   196  				switch a.Kind() {
   197  				case reflect.String:
   198  					x, _ := strconv.ParseFloat(a.String(), 64)
   199  					if x != (b.Float()) {
   200  						return false
   201  					}
   202  					return true
   203  				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   204  					x, _ := strconv.Atoi(b.String())
   205  					if x != int(a.Int()) {
   206  						return false
   207  					}
   208  					return true
   209  				}
   210  			}
   211  			t.Logf("value mismatch: %#v != %#v", a.Interface(), b.Interface())
   212  			return false
   213  		}
   214  	}
   215  	if a.Kind() == reflect.Map {
   216  		for _, k := range a.MapKeys() {
   217  			if !checkAInB(t, a.MapIndex(k), b.MapIndex(k), opts) {
   218  				return false
   219  			}
   220  		}
   221  	}
   222  	if a.Kind() == reflect.Slice {
   223  		for i := 0; i < a.Len(); i++ {
   224  			if !checkAInB(t, a.Index(i), b.Index(i), opts) {
   225  				return false
   226  			}
   227  		}
   228  	}
   229  	return true
   230  }
   231  
   232  func TestThriftResponseBase(t *testing.T) {
   233  	desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "ExampleMethod", thrift.Options{
   234  		EnableThriftBase: true,
   235  	}))
   236  	js := getExmaple3JSON()
   237  	cv := NewBinaryConv(conv.Options{
   238  		EnableThriftBase: true,
   239  	})
   240  	in := getExample3Data()
   241  
   242  	ctx := context.Background()
   243  	out, err := cv.Do(ctx, desc, in)
   244  	require.NoError(t, err)
   245  	var exp, act = new(example3.ExampleResp), new(example3.ExampleResp)
   246  	require.Nil(t, json.Unmarshal([]byte(js), &exp))
   247  	require.Nil(t, json.Unmarshal([]byte(out), &act))
   248  	require.Equal(t, exp, act)
   249  
   250  	b := base.NewBaseResp()
   251  	require.NoError(t, err)
   252  	ctx = context.WithValue(ctx, conv.CtxKeyThriftRespBase, b)
   253  	out, err = cv.Do(ctx, desc, in)
   254  	require.NoError(t, err)
   255  	exp, act = new(example3.ExampleResp), new(example3.ExampleResp)
   256  	require.Nil(t, json.Unmarshal([]byte(js), &exp))
   257  	require.Nil(t, json.Unmarshal([]byte(out), &act))
   258  	require.NotEqual(t, exp, act)
   259  	n, err := sjson.NewSearcher(js).GetByPath("BaseResp")
   260  	bj, err := n.Raw()
   261  	require.NoError(t, err)
   262  	require.Nil(t, json.Unmarshal([]byte(bj), &act.BaseResp))
   263  	require.Equal(t, (*base.BaseResp)(unsafe.Pointer(act.BaseResp)), b)
   264  }
   265  
   266  func TestAGWBodyDynamic(t *testing.T) {
   267  	cv := NewBinaryConv(conv.Options{
   268  		EnableValueMapping: true,
   269  	})
   270  	desc := getExampleErrorDesc()
   271  	exp := example3.NewExampleErrorResp()
   272  	exp.Int64 = 1
   273  	exp.Xjson = `{"b":1}`
   274  	ctx := context.Background()
   275  	in := make([]byte, exp.BLength())
   276  	_ = exp.FastWriteNocopy(in, nil)
   277  	out, err := cv.Do(ctx, desc, in)
   278  	require.NoError(t, err)
   279  	expj := (`{"Int64":1,"Xjson":{"b":1}}`)
   280  	require.Equal(t, expj, string(out))
   281  
   282  	cv.opts.EnableValueMapping = false
   283  	out, err = cv.Do(ctx, desc, in)
   284  	require.NoError(t, err)
   285  	require.Equal(t, (`{"Int64":1,"Xjson":"{\"b\":1}"}`), string(out))
   286  }
   287  
   288  func TestException(t *testing.T) {
   289  	cv := NewBinaryConv(conv.Options{
   290  		ConvertException: true,
   291  	})
   292  	desc := thrift.FnWholeResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "ExampleMethod", thrift.Options{}))
   293  
   294  	exp := example3.NewExampleServiceExampleMethodResult()
   295  	success := example3.NewExampleResp()
   296  	success.Status = 202
   297  	exception := example3.NewException()
   298  	exception.Code = 400
   299  	exception.Msg = "this is an exception"
   300  	exp.Success = success
   301  	exp.Err = exception
   302  	ctx := context.Background()
   303  	in := make([]byte, exp.BLength())
   304  	_ = exp.FastWriteNocopy(in, nil)
   305  	_, err := cv.Do(ctx, desc, in)
   306  	require.Error(t, err)
   307  	require.Equal(t, err.Error(), `{"code":400,"msg":"this is an exception"}`)
   308  }
   309  
   310  func TestInt2String(t *testing.T) {
   311  	cv := NewBinaryConv(conv.Options{
   312  		EnableValueMapping: true,
   313  	})
   314  	desc := getExampleInt2Float()
   315  	exp := example3.NewExampleInt2Float()
   316  	exp.Int32 = 1
   317  	exp.Int64 = 2
   318  	exp.Float64 = 3.14
   319  	exp.String_ = "hello"
   320  	exp.Subfix = 0.92653
   321  	ctx := context.Background()
   322  	in := make([]byte, exp.BLength())
   323  	_ = exp.FastWriteNocopy(in, nil)
   324  
   325  	out, err := cv.Do(ctx, desc, in)
   326  	require.NoError(t, err)
   327  	require.Equal(t, `{"Int32":"1","Float64":"3.14","Int64":2,"Subfix":0.92653,"中文":"hello"}`, string(out))
   328  
   329  	cv.opts.EnableValueMapping = false
   330  	out, err = cv.Do(ctx, desc, in)
   331  	require.NoError(t, err)
   332  	require.Equal(t, (`{"Int32":1,"Float64":3.14,"Int64":2,"Subfix":0.92653,"中文":"hello"}`), string(out))
   333  
   334  	cv.opts.Int642String = true
   335  	out, err = cv.Do(ctx, desc, in)
   336  	require.NoError(t, err)
   337  	require.Equal(t, (`{"Int32":1,"Float64":3.14,"Int64":"2","Subfix":0.92653,"中文":"hello"}`), string(out))
   338  }
   339  
   340  func TestHttpMappingFallback(t *testing.T) {
   341  	cv := NewBinaryConv(conv.Options{})
   342  	t.Run("not as extra", func(t *testing.T) {
   343  		desc := getExampleFallbackDesc()
   344  		exp := example3.NewExampleFallback()
   345  		exp.Msg = "hello"
   346  		exp.Heeader = "world"
   347  		in := make([]byte, exp.BLength())
   348  		_ = exp.FastWriteNocopy(in, nil)
   349  		expJSON := `{}`
   350  		cv.SetOptions(conv.Options{
   351  			EnableHttpMapping:      true,
   352  			WriteHttpValueFallback: false,
   353  			OmitHttpMappingErrors:  true,
   354  		})
   355  		ctx := context.Background()
   356  		resp := http.NewHTTPResponse()
   357  		ctx = context.WithValue(ctx, conv.CtxKeyHTTPResponse, resp)
   358  		out, err := cv.Do(ctx, desc, in)
   359  		if err != nil {
   360  			t.Fatal(err)
   361  		}
   362  		require.Equal(t, expJSON, string(out))
   363  		assert.Equal(t, "world", resp.Header["Heeader"][0])
   364  	})
   365  	t.Run("as extra", func(t *testing.T) {
   366  		desc := getExampleFallbackDesc()
   367  		exp := example3.NewExampleFallback()
   368  		exp.Msg = "hello"
   369  		exp.Heeader = "world"
   370  		in := make([]byte, exp.BLength())
   371  		_ = exp.FastWriteNocopy(in, nil)
   372  		expJSON := `{"Msg":"hello"}`
   373  		cv.SetOptions(conv.Options{
   374  			EnableHttpMapping:      true,
   375  			WriteHttpValueFallback: true,
   376  			OmitHttpMappingErrors:  true,
   377  		})
   378  		ctx := context.Background()
   379  		resp := http.NewHTTPResponse()
   380  		ctx = context.WithValue(ctx, conv.CtxKeyHTTPResponse, resp)
   381  		out, err := cv.Do(ctx, desc, in)
   382  		if err != nil {
   383  			t.Fatal(err)
   384  		}
   385  		require.Equal(t, expJSON, string(out))
   386  		assert.Equal(t, "world", resp.Header["Heeader"][0])
   387  	})
   388  }
   389  
   390  func TestWriteEmpty(t *testing.T) {
   391  	desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "ExampleMethod", thrift.Options{}))
   392  	p := thrift.NewBinaryProtocolBuffer()
   393  	p.WriteStructBegin("ExampleResp")
   394  	p.WriteFieldBegin("Status", thrift.I32, 3)
   395  	expStatus := int32(23)
   396  	p.WriteI32(expStatus)
   397  	p.WriteFieldEnd()
   398  	p.WriteStructEnd()
   399  	data := p.Buf
   400  	cv := NewBinaryConv(conv.Options{
   401  		WriteDefaultField: true,
   402  		EnableHttpMapping: true,
   403  	})
   404  	ctx := context.Background()
   405  	resp := http.NewHTTPResponse()
   406  	ctx = context.WithValue(ctx, conv.CtxKeyHTTPResponse, resp)
   407  	out, err := cv.Do(ctx, desc, data)
   408  	if err != nil {
   409  		t.Fatal(err)
   410  	}
   411  	var exp, act example3.ExampleResp
   412  	_, err = exp.FastRead(data)
   413  	require.NoError(t, err)
   414  	require.Nil(t, json.Unmarshal([]byte(out), &act))
   415  	assert.NotEqual(t, exp, act)
   416  	assert.Equal(t, int32(0), act.Status)
   417  	assert.Equal(t, expStatus, int32(resp.StatusCode))
   418  	assert.Equal(t, &kbase.BaseResp{
   419  		StatusMessage: "",
   420  		StatusCode:    0,
   421  		Extra:         map[string]string{},
   422  	}, act.BaseResp)
   423  }
   424  
   425  func TestUnknowFields(t *testing.T) {
   426  	t.Run("top", func(t *testing.T) {
   427  		desc := getExamplePartialDesc()
   428  		// js := getExmaple3JSON()
   429  		cv := NewBinaryConv(conv.Options{
   430  			DisallowUnknownField: true,
   431  		})
   432  		in := getExample3Data()
   433  		_, err := cv.Do(context.Background(), desc, in)
   434  		require.Error(t, err)
   435  		require.Equal(t, meta.ErrUnknownField, err.(meta.Error).Code.Behavior())
   436  	})
   437  
   438  	t.Run("nested", func(t *testing.T) {
   439  		desc := getExamplePartialDesc2()
   440  		// js := getExmaple3JSON()
   441  		cv := NewBinaryConv(conv.Options{
   442  			DisallowUnknownField: true,
   443  		})
   444  		in := getExample3Data()
   445  		_, err := cv.Do(context.Background(), desc, in)
   446  		require.Error(t, err)
   447  		require.Equal(t, meta.ErrUnknownField, err.(meta.Error).Code.Behavior())
   448  	})
   449  
   450  	t.Run("skip top", func(t *testing.T) {
   451  		desc := getExamplePartialDesc()
   452  		// js := getExmaple3JSON()
   453  		cv := NewBinaryConv(conv.Options{
   454  			DisallowUnknownField: false,
   455  		})
   456  		in := getExample3Data()
   457  		_, err := cv.Do(context.Background(), desc, in)
   458  		require.NoError(t, err)
   459  	})
   460  
   461  	t.Run("skip nested", func(t *testing.T) {
   462  		desc := getExamplePartialDesc2()
   463  		// js := getExmaple3JSON()
   464  		cv := NewBinaryConv(conv.Options{
   465  			DisallowUnknownField: false,
   466  		})
   467  		in := getExample3Data()
   468  		_, err := cv.Do(context.Background(), desc, in)
   469  		require.NoError(t, err)
   470  	})
   471  }
   472  
   473  func TestNobodyRequiredFields(t *testing.T) {
   474  	desc := GetDescByName("Base64BinaryMethod", true)
   475  
   476  	t.Run("base64 encode", func(t *testing.T) {
   477  		cv := NewBinaryConv(conv.Options{
   478  			EnableHttpMapping: true,
   479  			NoBase64Binary:    false,
   480  		})
   481  		exp := example3.NewExampleBase64Binary()
   482  		exp.Binary = []byte("hello")
   483  		exp.Binary2 = []byte("world")
   484  		in := make([]byte, exp.BLength())
   485  		_ = exp.FastWriteNocopy(in, nil)
   486  		resp := http.NewHTTPResponse()
   487  		ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPResponse, resp)
   488  		out, err := cv.Do(ctx, desc, in)
   489  		require.NoError(t, err)
   490  
   491  		act := example3.NewExampleBase64Binary()
   492  		err = json.Unmarshal(out, act)
   493  		require.NoError(t, err)
   494  		assert.Equal(t, exp.Binary, act.Binary)
   495  		assert.Equal(t, base64.StdEncoding.EncodeToString(exp.Binary2), resp.Response.Header["Binary2"][0])
   496  	})
   497  
   498  	t.Run("no base64 encode", func(t *testing.T) {
   499  		cv := NewBinaryConv(conv.Options{
   500  			EnableHttpMapping: true,
   501  			NoBase64Binary:    true,
   502  		})
   503  		exp := example3.NewExampleBase64Binary()
   504  		exp.Binary = []byte("hello")
   505  		exp.Binary2 = []byte("world")
   506  		in := make([]byte, exp.BLength())
   507  		_ = exp.FastWriteNocopy(in, nil)
   508  		resp := http.NewHTTPResponse()
   509  		ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPResponse, resp)
   510  		out, err := cv.Do(ctx, desc, in)
   511  		require.NoError(t, err)
   512  
   513  		act := struct {
   514  			Binary string `json:"Binary"`
   515  		}{}
   516  		err = json.Unmarshal(out, &act)
   517  		require.NoError(t, err)
   518  		assert.Equal(t, string(exp.Binary), act.Binary)
   519  		assert.Equal(t, string(exp.Binary2), resp.Response.Header["Binary2"][0])
   520  	})
   521  }
   522  
   523  func TestJSONString(t *testing.T) {
   524  	desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "JSONStringMethod", thrift.Options{}))
   525  	exp := example3.NewExampleJSONString()
   526  	eobj := &example3.JSONObject{
   527  		A: "1",
   528  		B: -1,
   529  	}
   530  	exp.Header = eobj
   531  	exp.Header2 = map[int32]string{1: "1"}
   532  	exp.Cookie = &example3.JSONObject{}
   533  	exp.Cookie2 = []int32{1, 2}
   534  	in := make([]byte, exp.BLength())
   535  	_ = exp.FastWriteNocopy(in, nil)
   536  
   537  	cv := NewBinaryConv(conv.Options{
   538  		EnableHttpMapping:      true,
   539  		WriteHttpValueFallback: true,
   540  		OmitHttpMappingErrors:  true,
   541  	})
   542  	ctx := context.Background()
   543  	resp := http.NewHTTPResponse()
   544  	ctx = context.WithValue(ctx, conv.CtxKeyHTTPResponse, resp)
   545  	out, err := cv.Do(ctx, desc, in)
   546  	require.NoError(t, err)
   547  
   548  	act := example3.NewExampleJSONString()
   549  	require.Equal(t, "{\"Query\":{},\"Query2\":[]}", string(out))
   550  	require.NoError(t, json.Unmarshal([]byte(resp.Response.Header.Get("header")), &act.Header))
   551  	require.Equal(t, exp.Header, act.Header)
   552  	require.NoError(t, json.Unmarshal([]byte(resp.Response.Header.Get("header2")), &act.Header2))
   553  	require.Equal(t, exp.Header2, act.Header2)
   554  	// require.NoError(t, json.Unmarshal([]byte(resp.Cookies()[0].Value), &act.Cookie))
   555  	// require.Equal(t, exp.Cookie, act.Cookie)
   556  	require.NoError(t, json.Unmarshal([]byte(resp.Cookies()[1].Value), &act.Cookie2))
   557  	require.Equal(t, exp.Cookie2, act.Cookie2)
   558  }
   559  
   560  func TestDefaultValue(t *testing.T) {
   561  	desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "DefaultValueMethod", thrift.Options{
   562  		UseDefaultValue: true,
   563  	}))
   564  	in := []byte{byte(thrift.STOP)}
   565  	t.Run("default value", func(t *testing.T) {
   566  		cv := NewBinaryConv(conv.Options{
   567  			EnableHttpMapping: true,
   568  			WriteDefaultField: true,
   569  		})
   570  		resp := http.NewHTTPResponse()
   571  		ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPResponse, resp)
   572  		out, err := cv.Do(ctx, desc, in)
   573  		require.NoError(t, err)
   574  		act := &example3.ExampleDefaultValue{}
   575  		err = json.Unmarshal(out, act)
   576  		require.NoError(t, err)
   577  
   578  		exp := example3.NewExampleDefaultValue()
   579  		exp.C = 0
   580  		exp.D = ""
   581  		assert.Equal(t, exp, act)
   582  		require.Equal(t, "1.2", resp.Response.Header.Get("c"))
   583  		require.Equal(t, "const string", resp.Response.Cookies()[0].Value)
   584  	})
   585  	t.Run("zero value", func(t *testing.T) {
   586  		desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "DefaultValueMethod", thrift.Options{
   587  			UseDefaultValue: false,
   588  		}))
   589  		cv := NewBinaryConv(conv.Options{
   590  			EnableHttpMapping: true,
   591  			WriteDefaultField: true,
   592  		})
   593  		resp := http.NewHTTPResponse()
   594  		ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPResponse, resp)
   595  		out, err := cv.Do(ctx, desc, in)
   596  		require.NoError(t, err)
   597  		act := &example3.ExampleDefaultValue{}
   598  		err = json.Unmarshal(out, act)
   599  		require.NoError(t, err)
   600  
   601  		exp := &example3.ExampleDefaultValue{}
   602  		assert.Equal(t, exp, act)
   603  		require.Equal(t, "0", resp.Response.Header.Get("c"))
   604  		require.Equal(t, "", resp.Response.Cookies()[0].Value)
   605  	})
   606  }
   607  
   608  func TestOptionalDefaultValue(t *testing.T) {
   609  	in := []byte{byte(thrift.STOP)}
   610  	t.Run("write required", func(t *testing.T) {
   611  		desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "OptionalDefaultValueMethod", thrift.Options{
   612  			UseDefaultValue: true,
   613  		}))
   614  		cv := NewBinaryConv(conv.Options{
   615  			EnableHttpMapping: true,
   616  			WriteRequireField: true,
   617  		})
   618  		resp := http.NewHTTPResponse()
   619  		ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPResponse, resp)
   620  		out, err := cv.Do(ctx, desc, in)
   621  		require.NoError(t, err)
   622  		act := &example3.ExampleOptionalDefaultValue{}
   623  		err = json.Unmarshal(out, act)
   624  		require.NoError(t, err)
   625  
   626  		exp := example3.NewExampleOptionalDefaultValue()
   627  		exp.A = ""
   628  		exp.C = 0
   629  		exp.D = ""
   630  		assert.Equal(t, exp, act)
   631  		require.Equal(t, "const string", resp.Response.Cookies()[0].Value)
   632  	})
   633  	t.Run("write required + write default + write optional", func(t *testing.T) {
   634  		desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "OptionalDefaultValueMethod", thrift.Options{
   635  			SetOptionalBitmap: true,
   636  			UseDefaultValue:   true,
   637  		}))
   638  		cv := NewBinaryConv(conv.Options{
   639  			EnableHttpMapping:  true,
   640  			WriteRequireField:  true,
   641  			WriteDefaultField:  true,
   642  			WriteOptionalField: true,
   643  		})
   644  		resp := http.NewHTTPResponse()
   645  		ctx := context.WithValue(context.Background(), conv.CtxKeyHTTPResponse, resp)
   646  		out, err := cv.Do(ctx, desc, in)
   647  		require.NoError(t, err)
   648  		spew.Dump(string(out))
   649  		act := &example3.ExampleOptionalDefaultValue{}
   650  		err = json.Unmarshal(out, act)
   651  		require.NoError(t, err)
   652  
   653  		exp := example3.NewExampleOptionalDefaultValue()
   654  		exp.C = 0
   655  		exp.D = ""
   656  		exp.E = new(string)
   657  		assert.Equal(t, exp, act)
   658  		require.Equal(t, "1.2", resp.Response.Header.Get("c"))
   659  		require.Equal(t, "const string", resp.Response.Cookies()[0].Value)
   660  		require.Equal(t, ``, resp.Response.Header.Get("f"))
   661  	})
   662  }
   663  
   664  func TestSimpleArgs(t *testing.T) {
   665  	cv := NewBinaryConv(conv.Options{})
   666  
   667  	t.Run("string", func(t *testing.T) {
   668  		desc := GetDescByName("String", false)
   669  		p := thrift.NewBinaryProtocolBuffer()
   670  		p.WriteString("hello")
   671  		in := p.Buf
   672  		out, err := cv.Do(context.Background(), desc, in)
   673  		require.NoError(t, err)
   674  		require.Equal(t, `"hello"`, string(out))
   675  	})
   676  
   677  	t.Run("int", func(t *testing.T) {
   678  		desc := GetDescByName("I64", false)
   679  		p := thrift.NewBinaryProtocolBuffer()
   680  		p.WriteI64(math.MaxInt64)
   681  		in := p.Buf
   682  		out, err := cv.Do(context.Background(), desc, in)
   683  		require.NoError(t, err)
   684  		require.Equal(t, strconv.Itoa(math.MaxInt64), string(out))
   685  	})
   686  }
   687  
   688  func TestConvThrift2HTTP_KitexApiHeader(t *testing.T) {
   689  	// annotation.RegisterHttpMaping(annotation.APIHeader, annotation.HttpMapingHandler{Req:annotation.ApiHeaderRequest, Resp:annotation.ApiheaderKitexResponse, Enc:annotation.ApiHeaderKitexEncoding})
   690  	
   691  	desc := thrift.FnResponse(thrift.GetFnDescFromFile("testdata/idl/example3.thrift", "JSONStringMethod", thrift.Options{}))
   692  	exp := example3.NewExampleJSONString()
   693  	eobj := &example3.JSONObject{
   694  		A: "1",
   695  		B: -1,
   696  	}
   697  	exp.Header = eobj
   698  	exp.Header2 = map[int32]string{1: "1"}
   699  	exp.Cookie = &example3.JSONObject{}
   700  	exp.Cookie2 = []int32{1, 2}
   701  	in := make([]byte, exp.BLength())
   702  	_ = exp.FastWriteNocopy(in, nil)
   703  
   704  	cv := NewBinaryConv(conv.Options{
   705  		EnableHttpMapping:      true,
   706  		WriteHttpValueFallback: true,
   707  		OmitHttpMappingErrors:  true,
   708  		UseKitexHttpEncoding: true,
   709  	})
   710  	ctx := context.Background()
   711  	resp := http.NewHTTPResponse()
   712  	ctx = context.WithValue(ctx, conv.CtxKeyHTTPResponse, resp)
   713  	out, err := cv.Do(ctx, desc, in)
   714  	require.NoError(t, err)
   715  
   716  	// act := example3.NewExampleJSONString()
   717  	require.Equal(t, "{\"Query\":{},\"Query2\":[]}", string(out))
   718  	require.Equal(t, "map[a:1 b:-1]", resp.Response.Header.Get("header"))
   719  	require.Equal(t, "map[1:1]", resp.Response.Header.Get("header2"))
   720  	require.Equal(t, "map[a: b:0]", resp.Cookies()[0].Value)
   721  	require.Equal(t, "1,2", resp.Cookies()[1].Value)
   722  
   723  	// annotation.RegisterHttpMaping(annotation.APIHeader, annotation.HttpMapingHandler{Req:annotation.ApiHeaderRequest, Resp: annotation.ApiHeaderResponse, Enc:annotation.ApiHeaderEncoding})
   724  }