github.com/cloudwego/dynamicgo@v0.2.6-0.20240519101509-707f41b6b834/thrift/generic/cast_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 generic
    18  
    19  import (
    20  	"fmt"
    21  	"reflect"
    22  	"strconv"
    23  	"strings"
    24  	"testing"
    25  
    26  	"github.com/cloudwego/dynamicgo/meta"
    27  	"github.com/cloudwego/dynamicgo/testdata/sample"
    28  	"github.com/cloudwego/dynamicgo/thrift"
    29  	"github.com/stretchr/testify/require"
    30  )
    31  
    32  var (
    33  	PathInnerBase              = NewPathFieldName("InnerBase")
    34  	PathNotExist               = []Path{NewPathFieldName("NotExist")}
    35  	PathExampleBool            = []Path{PathInnerBase, NewPathFieldId(thrift.FieldID(1))}
    36  	PathExampleByte            = []Path{PathInnerBase, NewPathFieldId(thrift.FieldID(2))}
    37  	PathExampleInt16           = []Path{PathInnerBase, NewPathFieldId(thrift.FieldID(3))}
    38  	PathExampleInt32           = []Path{PathInnerBase, NewPathFieldId(thrift.FieldID(4))}
    39  	PathExampleInt64           = []Path{PathInnerBase, NewPathFieldId(thrift.FieldID(5))}
    40  	PathExampleDouble          = []Path{PathInnerBase, NewPathFieldId(thrift.FieldID(6))}
    41  	PathExampleString          = []Path{PathInnerBase, NewPathFieldId(thrift.FieldID(7))}
    42  	PathExampleListInt32       = []Path{PathInnerBase, NewPathFieldId(thrift.FieldID(8))}
    43  	PathExampleMapStringString = []Path{PathInnerBase, NewPathFieldId(thrift.FieldID(9))}
    44  	PathExampleSetInt32_       = []Path{PathInnerBase, NewPathFieldId(thrift.FieldID(10))}
    45  	PathExampleFoo             = []Path{PathInnerBase, NewPathFieldId(thrift.FieldID(11))}
    46  	PathExampleMapInt32String  = []Path{PathInnerBase, NewPathFieldId(thrift.FieldID(12))}
    47  	PathExampleBinary          = []Path{PathInnerBase, NewPathFieldId(thrift.FieldID(13))}
    48  	PathExampleBase            = []Path{PathInnerBase, NewPathFieldId(thrift.FieldID(255))}
    49  )
    50  
    51  func TestCastInt8(t *testing.T) {
    52  	var exp = byte(129)
    53  	var n = NewNodeByte(exp)
    54  	act, err := n.Int()
    55  	require.Nil(t, err)
    56  	require.Equal(t, int(exp), act)
    57  }
    58  
    59  func TestCastAPI(t *testing.T) {
    60  	desc := getExampleDesc()
    61  	data := getExampleData()
    62  	var errUnsupportedType = errNode(meta.ErrUnsupportedType, "", nil)
    63  	var errNotFound = errNode(meta.ErrUnknownField, "", nil)
    64  	// var errInvalidParam = errNode(meta.ErrInvalidParam, "", nil)
    65  	var opts = &Options{}
    66  	cases := []testAPICase{
    67  		{path: PathNotExist, api: "Bool", exp: false, err: errNotFound},
    68  		{path: PathNotExist, api: "Byte", exp: byte(0), err: errNotFound},
    69  		{path: PathNotExist, api: "Int", exp: int(0), err: errNotFound},
    70  		{path: PathNotExist, api: "Float64", exp: float64(0), err: errNotFound},
    71  		{path: PathNotExist, api: "String", exp: "", err: errNotFound},
    72  		{path: PathNotExist, api: "Binary", exp: []byte(nil), err: errNotFound},
    73  		{path: PathNotExist, api: "List", exp: []interface{}(nil), err: errNotFound, args: []interface{}{opts}},
    74  		{path: PathNotExist, api: "StrMap", exp: map[string]interface{}(nil), err: errNotFound, args: []interface{}{opts}},
    75  		{path: PathNotExist, api: "IntMap", exp: map[int]interface{}(nil), err: errNotFound, args: []interface{}{opts}},
    76  		{path: PathNotExist, api: "Interface", exp: nil, err: errNotFound, args: []interface{}{opts}},
    77  
    78  		{path: PathExampleBool, api: "Bool", exp: sample.Example2Obj.InnerBase.Bool},
    79  		{path: PathExampleBool, api: "Byte", exp: byte(0), err: errUnsupportedType},
    80  		{path: PathExampleBool, api: "Int", exp: int(0), err: errUnsupportedType},
    81  		{path: PathExampleBool, api: "Float64", exp: float64(0), err: errUnsupportedType},
    82  		{path: PathExampleBool, api: "String", exp: "", err: errUnsupportedType},
    83  		{path: PathExampleBool, api: "Binary", exp: []byte(nil), err: errUnsupportedType},
    84  		{path: PathExampleBool, api: "List", exp: []interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
    85  		{path: PathExampleBool, api: "StrMap", exp: map[string]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
    86  		{path: PathExampleBool, api: "IntMap", exp: map[int]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
    87  		{path: PathExampleBool, api: "Interface", exp: sample.Example2Obj.InnerBase.Bool, args: []interface{}{opts}},
    88  
    89  		{path: PathExampleByte, api: "Bool", exp: false, err: errUnsupportedType},
    90  		{path: PathExampleByte, api: "Byte", exp: byte(sample.Example2Obj.InnerBase.Byte)},
    91  		{path: PathExampleByte, api: "Int", exp: int(sample.Example2Obj.InnerBase.Byte)},
    92  		{path: PathExampleByte, api: "Float64", exp: float64(0), err: errUnsupportedType},
    93  		{path: PathExampleByte, api: "String", exp: "", err: errUnsupportedType},
    94  		{path: PathExampleByte, api: "Binary", exp: []byte(nil), err: errUnsupportedType},
    95  		{path: PathExampleByte, api: "List", exp: []interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
    96  		{path: PathExampleByte, api: "StrMap", exp: map[string]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
    97  		{path: PathExampleByte, api: "IntMap", exp: map[int]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
    98  		{path: PathExampleByte, api: "Interface", exp: int(sample.Example2Obj.InnerBase.Byte), args: []interface{}{opts}},
    99  
   100  		{path: PathExampleInt16, api: "Bool", exp: false, err: errUnsupportedType},
   101  		{path: PathExampleInt16, api: "Byte", exp: byte(0), err: errUnsupportedType},
   102  		{path: PathExampleInt16, api: "Int", exp: int(sample.Example2Obj.InnerBase.Int16)},
   103  		{path: PathExampleInt16, api: "Float64", exp: float64(0), err: errUnsupportedType},
   104  		{path: PathExampleInt16, api: "String", exp: "", err: errUnsupportedType},
   105  		{path: PathExampleInt16, api: "Binary", exp: []byte(nil), err: errUnsupportedType},
   106  		{path: PathExampleInt16, api: "List", exp: []interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   107  		{path: PathExampleInt16, api: "StrMap", exp: map[string]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   108  		{path: PathExampleInt16, api: "IntMap", exp: map[int]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   109  		{path: PathExampleInt16, api: "Interface", exp: int(sample.Example2Obj.InnerBase.Int16), args: []interface{}{opts}},
   110  
   111  		{path: PathExampleInt32, api: "Bool", exp: false, err: errUnsupportedType},
   112  		{path: PathExampleInt32, api: "Byte", exp: byte(0), err: errUnsupportedType},
   113  		{path: PathExampleInt32, api: "Int", exp: int(sample.Example2Obj.InnerBase.Int32)},
   114  		{path: PathExampleInt32, api: "Float64", exp: float64(0), err: errUnsupportedType},
   115  		{path: PathExampleInt32, api: "String", exp: "", err: errUnsupportedType},
   116  		{path: PathExampleInt32, api: "Binary", exp: []byte(nil), err: errUnsupportedType},
   117  		{path: PathExampleInt32, api: "List", exp: []interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   118  		{path: PathExampleInt32, api: "StrMap", exp: map[string]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   119  		{path: PathExampleInt32, api: "IntMap", exp: map[int]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   120  		{path: PathExampleInt32, api: "Interface", exp: int(sample.Example2Obj.InnerBase.Int32), args: []interface{}{opts}},
   121  
   122  		{path: PathExampleInt64, api: "Bool", exp: false, err: errUnsupportedType},
   123  		{path: PathExampleInt64, api: "Byte", exp: byte(0), err: errUnsupportedType},
   124  		{path: PathExampleInt64, api: "Int", exp: int(sample.Example2Obj.InnerBase.Int64)},
   125  		{path: PathExampleInt64, api: "Float64", exp: float64(0), err: errUnsupportedType},
   126  		{path: PathExampleInt64, api: "String", exp: "", err: errUnsupportedType},
   127  		{path: PathExampleInt64, api: "Binary", exp: []byte(nil), err: errUnsupportedType},
   128  		{path: PathExampleInt64, api: "List", exp: []interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   129  		{path: PathExampleInt64, api: "StrMap", exp: map[string]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   130  		{path: PathExampleInt64, api: "IntMap", exp: map[int]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   131  		{path: PathExampleInt64, api: "Interface", exp: int(sample.Example2Obj.InnerBase.Int64), args: []interface{}{opts}},
   132  
   133  		{path: PathExampleDouble, api: "Bool", exp: false, err: errUnsupportedType},
   134  		{path: PathExampleDouble, api: "Byte", exp: byte(0), err: errUnsupportedType},
   135  		{path: PathExampleDouble, api: "Int", exp: int(0), err: errUnsupportedType},
   136  		{path: PathExampleDouble, api: "Float64", exp: sample.Example2Obj.InnerBase.Double},
   137  		{path: PathExampleDouble, api: "String", exp: "", err: errUnsupportedType},
   138  		{path: PathExampleDouble, api: "Binary", exp: []byte(nil), err: errUnsupportedType},
   139  		{path: PathExampleDouble, api: "List", exp: []interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   140  		{path: PathExampleDouble, api: "StrMap", exp: map[string]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   141  		{path: PathExampleDouble, api: "IntMap", exp: map[int]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   142  		{path: PathExampleDouble, api: "Interface", exp: float64(sample.Example2Obj.InnerBase.Double), args: []interface{}{opts}},
   143  
   144  		{path: PathExampleString, api: "Bool", exp: false, err: errUnsupportedType},
   145  		{path: PathExampleString, api: "Byte", exp: byte(0), err: errUnsupportedType},
   146  		{path: PathExampleString, api: "Int", exp: int(0), err: errUnsupportedType},
   147  		{path: PathExampleString, api: "Float64", exp: float64(0), err: errUnsupportedType},
   148  		{path: PathExampleString, api: "String", exp: sample.Example2Obj.InnerBase.String_},
   149  		{path: PathExampleString, api: "Binary", exp: []byte(sample.Example2Obj.InnerBase.String_)},
   150  		{path: PathExampleString, api: "List", exp: []interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   151  		{path: PathExampleString, api: "StrMap", exp: map[string]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   152  		{path: PathExampleString, api: "IntMap", exp: map[int]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   153  		{path: PathExampleString, api: "Interface", exp: string(sample.Example2Obj.InnerBase.String_), args: []interface{}{opts}},
   154  
   155  		{path: PathExampleBinary, api: "Bool", exp: false, err: errUnsupportedType},
   156  		{path: PathExampleBinary, api: "Byte", exp: byte(0), err: errUnsupportedType},
   157  		{path: PathExampleBinary, api: "Int", exp: int(0), err: errUnsupportedType},
   158  		{path: PathExampleBinary, api: "Float64", exp: float64(0), err: errUnsupportedType},
   159  		{path: PathExampleBinary, api: "String", exp: string(sample.Example2Obj.InnerBase.Binary)},
   160  		{path: PathExampleBinary, api: "Binary", exp: []byte(sample.Example2Obj.InnerBase.Binary)},
   161  		{path: PathExampleBinary, api: "List", exp: []interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   162  		{path: PathExampleBinary, api: "StrMap", exp: map[string]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   163  		{path: PathExampleBinary, api: "IntMap", exp: map[int]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   164  		{path: PathExampleBinary, api: "Interface", exp: string(sample.Example2Obj.InnerBase.Binary), args: []interface{}{opts}},
   165  
   166  		{path: PathExampleFoo, api: "Bool", exp: false, err: errUnsupportedType},
   167  		{path: PathExampleFoo, api: "Byte", exp: byte(0), err: errUnsupportedType},
   168  		{path: PathExampleFoo, api: "Int", exp: int(sample.Example2Obj.InnerBase.Foo)},
   169  		{path: PathExampleFoo, api: "Float64", exp: float64(0), err: errUnsupportedType},
   170  		{path: PathExampleFoo, api: "String", exp: "", err: errUnsupportedType},
   171  		{path: PathExampleFoo, api: "Binary", exp: []byte(nil), err: errUnsupportedType},
   172  		{path: PathExampleFoo, api: "List", exp: []interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   173  		{path: PathExampleFoo, api: "StrMap", exp: map[string]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   174  		{path: PathExampleFoo, api: "IntMap", exp: map[int]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   175  		{path: PathExampleFoo, api: "Interface", exp: int(sample.Example2Obj.InnerBase.Foo), args: []interface{}{opts}},
   176  
   177  		{path: PathExampleListInt32, api: "Bool", exp: false, err: errUnsupportedType},
   178  		{path: PathExampleListInt32, api: "Byte", exp: byte(0), err: errUnsupportedType},
   179  		{path: PathExampleListInt32, api: "Int", exp: int(0), err: errUnsupportedType},
   180  		{path: PathExampleListInt32, api: "Float64", exp: float64(0), err: errUnsupportedType},
   181  		{path: PathExampleListInt32, api: "String", exp: "", err: errUnsupportedType},
   182  		{path: PathExampleListInt32, api: "Binary", exp: []byte(nil), err: errUnsupportedType},
   183  		{path: PathExampleListInt32, api: "List", exp: toInterface(sample.Example2Obj.InnerBase.ListInt32), args: []interface{}{opts}},
   184  		{path: PathExampleListInt32, api: "StrMap", exp: map[string]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   185  		{path: PathExampleListInt32, api: "IntMap", exp: map[int]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   186  		{path: PathExampleListInt32, api: "Interface", exp: toInterface(sample.Example2Obj.InnerBase.ListInt32), args: []interface{}{opts}},
   187  
   188  		{path: PathExampleSetInt32_, api: "Bool", exp: false, err: errUnsupportedType},
   189  		{path: PathExampleSetInt32_, api: "Byte", exp: byte(0), err: errUnsupportedType},
   190  		{path: PathExampleSetInt32_, api: "Int", exp: int(0), err: errUnsupportedType},
   191  		{path: PathExampleSetInt32_, api: "Float64", exp: float64(0), err: errUnsupportedType},
   192  		{path: PathExampleSetInt32_, api: "String", exp: "", err: errUnsupportedType},
   193  		{path: PathExampleSetInt32_, api: "Binary", exp: []byte(nil), err: errUnsupportedType},
   194  		{path: PathExampleSetInt32_, api: "List", exp: toInterface(sample.Example2Obj.InnerBase.ListInt32), args: []interface{}{opts}},
   195  		{path: PathExampleSetInt32_, api: "StrMap", exp: map[string]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   196  		{path: PathExampleSetInt32_, api: "IntMap", exp: map[int]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   197  		{path: PathExampleSetInt32_, api: "Interface", exp: toInterface(sample.Example2Obj.InnerBase.ListInt32), args: []interface{}{opts}},
   198  
   199  		{path: PathExampleMapInt32String, api: "Bool", exp: false, err: errUnsupportedType},
   200  		{path: PathExampleMapInt32String, api: "Byte", exp: byte(0), err: errUnsupportedType},
   201  		{path: PathExampleMapInt32String, api: "Int", exp: int(0), err: errUnsupportedType},
   202  		{path: PathExampleMapInt32String, api: "Float64", exp: float64(0), err: errUnsupportedType},
   203  		{path: PathExampleMapInt32String, api: "String", exp: "", err: errUnsupportedType},
   204  		{path: PathExampleMapInt32String, api: "Binary", exp: []byte(nil), err: errUnsupportedType},
   205  		{path: PathExampleMapInt32String, api: "List", exp: []interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   206  		{path: PathExampleMapInt32String, api: "StrMap", exp: map[string]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   207  		{path: PathExampleMapInt32String, api: "IntMap", exp: toInterface(sample.Example2Obj.InnerBase.MapInt32String), args: []interface{}{opts}},
   208  		{path: PathExampleMapInt32String, api: "Interface", exp: toInterface(sample.Example2Obj.InnerBase.MapInt32String), args: []interface{}{opts}},
   209  
   210  		{path: PathExampleMapStringString, api: "Bool", exp: false, err: errUnsupportedType},
   211  		{path: PathExampleMapStringString, api: "Byte", exp: byte(0), err: errUnsupportedType},
   212  		{path: PathExampleMapStringString, api: "Int", exp: int(0), err: errUnsupportedType},
   213  		{path: PathExampleMapStringString, api: "Float64", exp: float64(0), err: errUnsupportedType},
   214  		{path: PathExampleMapStringString, api: "String", exp: "", err: errUnsupportedType},
   215  		{path: PathExampleMapStringString, api: "Binary", exp: []byte(nil), err: errUnsupportedType},
   216  		{path: PathExampleMapStringString, api: "List", exp: []interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   217  		{path: PathExampleMapStringString, api: "StrMap", exp: toInterface(sample.Example2Obj.InnerBase.MapStringString), args: []interface{}{opts}},
   218  		{path: PathExampleMapStringString, api: "IntMap", exp: map[int]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   219  		{path: PathExampleMapStringString, api: "Interface", exp: toInterface(sample.Example2Obj.InnerBase.MapStringString), args: []interface{}{opts}},
   220  		{path: PathExampleMapStringString, api: "Interface", exp: toInterface2(sample.Example2Obj.InnerBase.MapStringString, false, 2), args: []interface{}{&Options{
   221  			CastStringAsBinary: true,
   222  		}}},
   223  
   224  		{path: PathExampleBase, api: "Bool", exp: false, err: errUnsupportedType},
   225  		{path: PathExampleBase, api: "Byte", exp: byte(0), err: errUnsupportedType},
   226  		{path: PathExampleBase, api: "Int", exp: int(0), err: errUnsupportedType},
   227  		{path: PathExampleBase, api: "Float64", exp: float64(0), err: errUnsupportedType},
   228  		{path: PathExampleBase, api: "String", exp: "", err: errUnsupportedType},
   229  		{path: PathExampleBase, api: "Binary", exp: []byte(nil), err: errUnsupportedType},
   230  		{path: PathExampleBase, api: "List", exp: []interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   231  		{path: PathExampleBase, api: "StrMap", exp: map[string]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   232  		{path: PathExampleBase, api: "IntMap", exp: map[int]interface{}(nil), err: errUnsupportedType, args: []interface{}{opts}},
   233  		{path: PathExampleBase, api: "Interface", exp: toInterface2(sample.Example2Obj.InnerBase.Base, false, 0), args: []interface{}{opts}},
   234  		{path: PathExampleBase, api: "Interface", exp: toInterface2(sample.Example2Obj.InnerBase.Base, true, 0), args: []interface{}{&Options{
   235  			MapStructById: true,
   236  		}}},
   237  	}
   238  	root := NewValue(desc, data)
   239  	for _, c := range cases {
   240  		t.Run(fmt.Sprintf(c.path[len(c.path)-1].String())+c.api, func(t *testing.T) {
   241  			APIHelper(t, &root, nil, c)
   242  		})
   243  	}
   244  }
   245  
   246  type testAPICase struct {
   247  	name      string
   248  	path      []Path
   249  	api       string
   250  	args      []interface{}
   251  	exp       interface{}
   252  	err       error
   253  	strictErr bool
   254  }
   255  
   256  func APIHelper(t *testing.T, root *Value, val *Value, c testAPICase) {
   257  	if val == nil {
   258  		t := root.GetByPath(c.path...)
   259  		val = &t
   260  	}
   261  	// require.Nil(t, val.Check())
   262  	vt := reflect.ValueOf(val)
   263  	mt := vt.MethodByName(c.api)
   264  
   265  	var args []reflect.Value
   266  	if len(c.args) > 0 {
   267  		args = make([]reflect.Value, len(c.args))
   268  		for i, arg := range c.args {
   269  			args[i] = reflect.ValueOf(arg)
   270  		}
   271  	}
   272  
   273  	rs := mt.Call(args)
   274  	var e interface{}
   275  	if len(rs) == 2 {
   276  		e = rs[1].Interface()
   277  	} else {
   278  		e = rs[0].Interface()
   279  	}
   280  
   281  	require.Equal(t, c.err == nil, e == nil)
   282  	if e != nil {
   283  		if n, ok := c.err.(Value); ok {
   284  			n2, ok2 := e.(Value)
   285  			if !ok2 {
   286  				n3, ok3 := e.(Node)
   287  				if !ok3 {
   288  					t.Fatal("not a node erro ")
   289  				} else {
   290  					require.Equal(t, n.ErrCode(), n3.ErrCode())
   291  				}
   292  			}
   293  			require.Equal(t, n.ErrCode(), n2.ErrCode())
   294  		} else if nn, ok := c.err.(meta.Error); ok {
   295  			nn2, ok2 := e.(meta.Error)
   296  			if !ok2 {
   297  				n3, ok3 := e.(Node)
   298  				if !ok3 {
   299  					t.Fatal("not a node erro ")
   300  				} else {
   301  					require.Equal(t, nn.Code.Behavior(), n3.ErrCode().Behavior())
   302  				}
   303  			} else {
   304  				require.True(t, ok2)
   305  				require.Equal(t, nn.Code.Behavior(), nn2.Code.Behavior())
   306  			}
   307  		}
   308  		if c.strictErr {
   309  			require.Equal(t, c.err, e.(error))
   310  		}
   311  	}
   312  	if len(rs) >= 2 {
   313  		require.Equal(t, c.exp, rs[0].Interface())
   314  	}
   315  }
   316  
   317  func toInterface(v interface{}) interface{} {
   318  	return toInterface2(v, false, none)
   319  }
   320  
   321  var bytesType = reflect.TypeOf([]byte{})
   322  
   323  const (
   324  	none int = 0
   325  	b2s  int = 1
   326  	s2b  int = 2
   327  )
   328  
   329  func toInterface2(v interface{}, fieldId bool, byte2string int) interface{} {
   330  	vt := reflect.ValueOf(v)
   331  	if vt.Kind() == reflect.Ptr {
   332  		if vt.IsNil() {
   333  			return nil
   334  		}
   335  		vt = vt.Elem()
   336  	}
   337  	if k := vt.Kind(); k == reflect.Slice || k == reflect.Array {
   338  		if vt.Type() == bytesType {
   339  			if byte2string == b2s {
   340  				return string(vt.Bytes())
   341  			} else {
   342  				return vt.Bytes()
   343  			}
   344  		}
   345  		var r = make([]interface{}, 0, vt.Len())
   346  		for i := 0; i < vt.Len(); i++ {
   347  			vv := toInterface2(vt.Index(i).Interface(), fieldId, byte2string)
   348  			if vv != nil {
   349  				r = append(r, vv)
   350  			}
   351  		}
   352  		return r
   353  	} else if k == reflect.Map {
   354  		if kt := vt.Type().Key().Kind(); kt == reflect.String {
   355  			var r = make(map[string]interface{}, vt.Len())
   356  			for _, k := range vt.MapKeys() {
   357  				vv := toInterface2(vt.MapIndex(k).Interface(), fieldId, byte2string)
   358  				if vv != nil {
   359  					r[k.String()] = vv
   360  				}
   361  			}
   362  			return r
   363  		} else if kt == reflect.Int || kt == reflect.Int8 || kt == reflect.Int16 || kt == reflect.Int32 || kt == reflect.Int64 {
   364  			var r = make(map[int]interface{}, vt.Len())
   365  			for _, k := range vt.MapKeys() {
   366  				vv := toInterface2(vt.MapIndex(k).Interface(), fieldId, byte2string)
   367  				if vv != nil {
   368  					r[int(k.Int())] = vv
   369  				}
   370  			}
   371  			return r
   372  		} else {
   373  			var r = make(map[interface{}]interface{}, vt.Len())
   374  			for _, k := range vt.MapKeys() {
   375  				kv := toInterface2(k.Interface(), fieldId, byte2string)
   376  				vv := toInterface2(vt.MapIndex(k).Interface(), fieldId, byte2string)
   377  				if kv != nil && vv != nil {
   378  					switch t := kv.(type) {
   379  					case map[string]interface{}:
   380  						r[&t] = vv
   381  					case map[int]interface{}:
   382  						r[&t] = vv
   383  					case map[interface{}]interface{}:
   384  						r[&t] = vv
   385  					case []interface{}:
   386  						r[&t] = vv
   387  					default:
   388  						r[kv] = vv
   389  					}
   390  				}
   391  			}
   392  			return r
   393  		}
   394  	} else if k == reflect.Struct {
   395  		var r interface{}
   396  		if fieldId {
   397  			r = map[thrift.FieldID]interface{}{}
   398  		} else {
   399  			r = map[int]interface{}{}
   400  		}
   401  		for i := 0; i < vt.NumField(); i++ {
   402  			field := vt.Type().Field(i)
   403  			tag := field.Tag.Get("thrift")
   404  			ts := strings.Split(tag, ",")
   405  			id := i
   406  			if len(ts) > 1 {
   407  				id, _ = strconv.Atoi(ts[1])
   408  			}
   409  			vv := toInterface2(vt.Field(i).Interface(), fieldId, byte2string)
   410  			if vv != nil {
   411  				if fieldId {
   412  					r.(map[thrift.FieldID]interface{})[thrift.FieldID(id)] = vv
   413  				} else {
   414  					r.(map[int]interface{})[int(id)] = vv
   415  				}
   416  			}
   417  		}
   418  		return r
   419  	} else if k == reflect.Int || k == reflect.Int8 || k == reflect.Int16 || k == reflect.Int32 || k == reflect.Int64 {
   420  		return int(vt.Int())
   421  	} else if k == reflect.String {
   422  		if byte2string == s2b {
   423  			return []byte(vt.String())
   424  		} else {
   425  			return vt.String()
   426  		}
   427  	}
   428  	return vt.Interface()
   429  }
   430  
   431  func specialFieldName(name string) string {
   432  	if len(name) > 0 && name[len(name)-1] == '_' {
   433  		return name[:len(name)-1]
   434  	}
   435  	return name
   436  }