github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/reflector/reflector_test.go (about)

     1  package reflector
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"reflect"
     7  	"sort"
     8  	"testing"
     9  
    10  	"github.com/stretchr/testify/assert"
    11  )
    12  
    13  // TestStruct ...
    14  type TestStruct struct {
    15  	_          int `bu:"ba"`
    16  	Exported   string
    17  	unexported int `aaa:"bbb" ccc:"ddd"`
    18  }
    19  
    20  func init() {
    21  	var ts TestStruct
    22  	_ = ts.unexported
    23  }
    24  
    25  type Address struct {
    26  	Street string `tag:"be" tag2:"1,2,3"`
    27  	Number int    `tag:"bi"`
    28  }
    29  
    30  type Person struct {
    31  	Name string `tag:"bu"`
    32  	Address
    33  }
    34  
    35  func (p Person) Add(a, b, c int) int    { return a + b + c }
    36  func (p *Person) Subtract(a, b int) int { return a - b }
    37  func (p Person) ReturnsError(err bool) (string, *int, error) {
    38  	i := 2
    39  	if err {
    40  		return "", nil, errors.New("error here")
    41  	}
    42  	return "jen", &i, nil
    43  }
    44  
    45  type CustomType int
    46  
    47  func (ct CustomType) Method1() string { return "yep" }
    48  func (ct *CustomType) Method2() int   { return 7 }
    49  
    50  func (p Person) Hi(name string) string {
    51  	return fmt.Sprintf("Hi %s my name is %s", name, p.Name)
    52  }
    53  
    54  type Company struct {
    55  	Address
    56  	Number int `tag:"bi"`
    57  }
    58  
    59  // TestDoubleFields checks that there are no "double" fields (or fields shadowing)
    60  func TestDoubleFields(t *testing.T) {
    61  	t.Parallel()
    62  	structs := []interface{}{
    63  		Obj{},
    64  		ObjField{},
    65  		ObjMethod{},
    66  		ObjMetadata{},
    67  		ObjFieldMetadata{},
    68  		ObjMethodMetadata{},
    69  	}
    70  	for _, s := range structs {
    71  		double := New(s).FindDoubleFields()
    72  		assert.Equal(t, 0, len(double))
    73  	}
    74  }
    75  
    76  func TestString(t *testing.T) {
    77  	t.Parallel()
    78  	assert.Equal(t, "reflector.Person", New(Person{}).String())
    79  	assert.Equal(t, "*reflector.Person", New(&Person{}).String())
    80  	assert.Equal(t, "nil", New(nil).String())
    81  	assert.Equal(t, "int", New(1).String())
    82  	var i int
    83  	assert.Equal(t, "*int", New(&i).String())
    84  
    85  	// Check that when we twice get a field, the metadata field is cached only once:
    86  	assert.Equal(t, New(Person{}).Field("bu").ObjFieldMetadata, New(Person{}).Field("bu").ObjFieldMetadata)
    87  	assert.Equal(t, New(&Person{}).Field("bu").ObjFieldMetadata, New(&Person{}).Field("bu").ObjFieldMetadata)
    88  	assert.Equal(t, New(Person{}).Field("Address").ObjFieldMetadata, New(Person{}).Field("Address").ObjFieldMetadata)
    89  	assert.Equal(t, New(&Person{}).Field("bu").ObjFieldMetadata, New(&Person{}).Field("bu").ObjFieldMetadata)
    90  }
    91  
    92  func TestNilStringPtr(t *testing.T) {
    93  	t.Parallel()
    94  	assert.Equal(t, "*string", New((*string)(nil)).String())
    95  	assert.Equal(t, 0, len(New((*string)(nil)).Fields()))
    96  	assert.Equal(t, 0, len(New((*string)(nil)).Methods()))
    97  
    98  	v, err := New((*string)(nil)).Field("Bu").Get()
    99  	assert.Nil(t, v)
   100  	assert.NotNil(t, err)
   101  }
   102  
   103  func TestNilStructPtr(t *testing.T) {
   104  	t.Parallel()
   105  	assert.Equal(t, "*reflector.Person", New((*Person)(nil)).String())
   106  	assert.Equal(t, 2, len(New((*Person)(nil)).Fields()))
   107  	assert.Equal(t, 4, len(New((*Person)(nil)).Methods()))
   108  
   109  	err := New((*Person)(nil)).Field("Number").Set(17)
   110  	assert.NotNil(t, err)
   111  
   112  	v, err := New((*Person)(nil)).Field("Bu").Get()
   113  	assert.Nil(t, v)
   114  	assert.NotNil(t, err)
   115  }
   116  
   117  func TestListFieldsFlattened(t *testing.T) {
   118  	t.Parallel()
   119  	p := Person{}
   120  	obj := New(p)
   121  
   122  	assert.True(t, obj.IsValid())
   123  	assert.False(t, obj.IsPtr())
   124  	assert.True(t, obj.IsStructOrPtrToStruct())
   125  
   126  	fields := obj.FieldsFlattened()
   127  	assert.Equal(t, 3, len(fields))
   128  	assert.Equal(t, fields[0].Name(), "Name")
   129  	assert.Equal(t, fields[1].Name(), "Street")
   130  	assert.Equal(t, fields[2].Name(), "Number")
   131  
   132  	assert.True(t, obj.Field("Name").IsValid())
   133  
   134  	kind := obj.Field("Name").Kind()
   135  	assert.Equal(t, reflect.String, kind)
   136  
   137  	kind = obj.Field("BuName").Kind()
   138  	assert.Equal(t, reflect.Invalid, kind)
   139  
   140  	ty := obj.Field("Number").Type()
   141  	assert.Equal(t, reflect.TypeOf(1), ty)
   142  
   143  	ty = obj.Field("Istra").Type()
   144  	assert.Nil(t, ty)
   145  }
   146  
   147  func TestListFields(t *testing.T) {
   148  	t.Parallel()
   149  	p := Person{}
   150  	obj := New(p)
   151  
   152  	fields := obj.Fields()
   153  	assert.Equal(t, len(fields), 2)
   154  	assert.Equal(t, fields[0].Name(), "Name")
   155  	assert.Equal(t, fields[1].Name(), "Address")
   156  }
   157  
   158  func TestListFieldsAll(t *testing.T) {
   159  	t.Parallel()
   160  	p := Person{}
   161  	obj := New(p)
   162  
   163  	fields := obj.FieldsAll()
   164  	assert.Equal(t, len(fields), 4)
   165  	assert.Equal(t, fields[0].Name(), "Name")
   166  	assert.Equal(t, fields[1].Name(), "Address")
   167  	assert.Equal(t, fields[2].Name(), "Street")
   168  	assert.Equal(t, fields[3].Name(), "Number")
   169  }
   170  
   171  func TestListFieldsAnonymous(t *testing.T) {
   172  	t.Parallel()
   173  	p := Person{}
   174  	obj := New(p)
   175  
   176  	fields := obj.FieldsAnonymous()
   177  	assert.Equal(t, 1, len(fields))
   178  	assert.Equal(t, fields[0].Name(), "Address")
   179  }
   180  
   181  func TestListFieldsAllWithDoubleFields(t *testing.T) {
   182  	t.Parallel()
   183  	obj := New(Company{})
   184  
   185  	fields := obj.FieldsAll()
   186  	assert.Equal(t, len(fields), 4)
   187  	assert.Equal(t, fields[0].Name(), "Address")
   188  	assert.Equal(t, fields[1].Name(), "Street")
   189  	// Number is declared both in Company and in Address, so listed twice here:
   190  	assert.Equal(t, fields[2].Name(), "Number")
   191  	assert.Equal(t, fields[3].Name(), "Number")
   192  }
   193  
   194  func TestFindDoubleFields(t *testing.T) {
   195  	t.Parallel()
   196  	obj := New(Company{})
   197  
   198  	fields := obj.FindDoubleFields()
   199  	assert.Equal(t, 1, len(fields))
   200  	assert.Equal(t, fields[0], "Number")
   201  }
   202  
   203  func TestListFieldsOnPointer(t *testing.T) {
   204  	t.Parallel()
   205  	p := &Person{}
   206  	obj := New(p)
   207  
   208  	assert.True(t, obj.IsPtr())
   209  	assert.True(t, obj.IsStructOrPtrToStruct())
   210  
   211  	fields := obj.Fields()
   212  	assert.Equal(t, len(fields), 2)
   213  	assert.Equal(t, fields[0].Name(), "Name")
   214  	assert.Equal(t, fields[1].Name(), "Address")
   215  
   216  	kind := obj.Field("Name").Kind()
   217  	assert.Equal(t, reflect.String, kind)
   218  
   219  	kind = obj.Field("BuName").Kind()
   220  	assert.Equal(t, reflect.Invalid, kind)
   221  
   222  	ty := obj.Field("Number").Type()
   223  	assert.Equal(t, reflect.TypeOf(1), ty)
   224  
   225  	ty = obj.Field("Istra").Type()
   226  	assert.Nil(t, ty)
   227  }
   228  
   229  func TestListFieldsFlattenedOnPointer(t *testing.T) {
   230  	t.Parallel()
   231  	p := &Person{}
   232  	obj := New(p)
   233  
   234  	fields := obj.FieldsFlattened()
   235  	assert.Equal(t, len(fields), 3)
   236  	assert.Equal(t, fields[0].Name(), "Name")
   237  	assert.Equal(t, fields[1].Name(), "Street")
   238  	assert.Equal(t, fields[2].Name(), "Number")
   239  }
   240  
   241  func TestNoFieldsNoCustomType(t *testing.T) {
   242  	t.Parallel()
   243  	assert.Equal(t, len(New(CustomType(1)).Fields()), 0)
   244  	ct := CustomType(2)
   245  	assert.Equal(t, len(New(&ct).Fields()), 0)
   246  }
   247  
   248  func TestIsStructForCustomTypes(t *testing.T) {
   249  	t.Parallel()
   250  	ct := CustomType(2)
   251  	assert.False(t, New(CustomType(1)).IsPtr())
   252  	assert.True(t, New(&ct).IsPtr())
   253  	assert.False(t, New(CustomType(1)).IsStructOrPtrToStruct())
   254  	assert.False(t, New(&ct).IsStructOrPtrToStruct())
   255  }
   256  
   257  func TestFieldValidity(t *testing.T) {
   258  	t.Parallel()
   259  	assert.False(t, New(CustomType(1)).Field("jkljkl").IsValid())
   260  	assert.True(t, New(Person{}).Field("street").IsValid())
   261  	assert.True(t, New(Person{}).Field("Street").IsValid())
   262  	assert.True(t, New(Person{}).Field("Number").IsValid())
   263  	assert.True(t, New(Person{}).Field("Name").IsValid())
   264  }
   265  
   266  func TestSetFieldNonPointer(t *testing.T) {
   267  	t.Parallel()
   268  	p := Person{}
   269  	obj := New(p)
   270  	assert.False(t, obj.IsPtr())
   271  
   272  	field := obj.Field("Street")
   273  	assert.False(t, field.IsSettable())
   274  
   275  	err := field.Set("ulica")
   276  	assert.Error(t, err)
   277  
   278  	value, err := field.Get()
   279  	assert.Nil(t, err)
   280  	assert.Equal(t, "", value)
   281  
   282  	assert.Equal(t, "", p.Street)
   283  
   284  	street, err := obj.Field("Street").Get()
   285  	assert.Nil(t, err)
   286  
   287  	// This actually don't work because p is a struct and reflector is working on it's own copy:
   288  	assert.Equal(t, "", street)
   289  }
   290  
   291  func TestSetField(t *testing.T) {
   292  	t.Parallel()
   293  	p := Person{}
   294  	obj := New(&p)
   295  	assert.True(t, obj.IsPtr())
   296  
   297  	field := obj.Field("Street")
   298  	assert.True(t, field.IsSettable())
   299  
   300  	err := field.Set("ulica")
   301  	assert.Nil(t, err)
   302  
   303  	value, err := field.Get()
   304  	assert.Nil(t, err)
   305  	assert.Equal(t, "ulica", value)
   306  
   307  	assert.Equal(t, "ulica", p.Street)
   308  }
   309  
   310  func TestCustomTypeMethods(t *testing.T) {
   311  	t.Parallel()
   312  	assert.Equal(t, len(New(CustomType(1)).Methods()), 1)
   313  	ct := CustomType(1)
   314  	assert.Equal(t, len(New(&ct).Methods()), 2)
   315  }
   316  
   317  func TestMethods(t *testing.T) {
   318  	t.Parallel()
   319  	assert.Equal(t, len(New(Person{}).Methods()), 3)
   320  	assert.Equal(t, len(New(&Person{}).Methods()), 4)
   321  
   322  	// Check that when we twice get a field, the metadata field is cached only once:
   323  	assert.Equal(t, New(Person{}).Method("Add").ObjMethodMetadata, New(Person{}).Method("Add").ObjMethodMetadata)
   324  	assert.Equal(t, New(&Person{}).Method("Add").ObjMethodMetadata, New(&Person{}).Method("Add").ObjMethodMetadata)
   325  }
   326  
   327  func TestCallMethod(t *testing.T) {
   328  	t.Parallel()
   329  	obj := New(&Person{})
   330  	method := obj.Method("Add")
   331  	res, err := method.Call(2, 3, 6)
   332  	assert.Nil(t, err)
   333  	assert.False(t, res.IsError())
   334  	assert.Equal(t, len(res.Result), 1)
   335  	assert.Equal(t, res.Result[0], 11)
   336  
   337  	assert.True(t, method.IsValid())
   338  	assert.Equal(t, len(method.InTypes()), 3)
   339  	assert.Equal(t, len(method.OutTypes()), 1)
   340  
   341  	sub, err := obj.Method("Subtract").Call(5, 6)
   342  	assert.Nil(t, err)
   343  	assert.Equal(t, sub.Result, []interface{}{-1})
   344  }
   345  
   346  func TestCallInvalidMethod(t *testing.T) {
   347  	t.Parallel()
   348  	obj := New(&Person{})
   349  	method := obj.Method("AddAdddd")
   350  	res, err := method.Call([]interface{}{2, 3, 6})
   351  	assert.NotNil(t, err)
   352  	assert.Nil(t, res)
   353  
   354  	assert.Equal(t, len(method.InTypes()), 0)
   355  	assert.Equal(t, len(method.OutTypes()), 0)
   356  }
   357  
   358  func TestMethodsValidityOnPtr(t *testing.T) {
   359  	t.Parallel()
   360  	ct := CustomType(1)
   361  	obj := New(&ct)
   362  
   363  	assert.True(t, obj.IsPtr())
   364  
   365  	assert.True(t, obj.Method("Method1").IsValid())
   366  	assert.True(t, obj.Method("Method2").IsValid())
   367  
   368  	{
   369  		res, err := obj.Method("Method1").Call()
   370  		assert.Nil(t, err)
   371  		assert.Equal(t, res.Result, []interface{}{"yep"})
   372  	}
   373  	{
   374  		res, err := obj.Method("Method2").Call()
   375  		assert.Nil(t, err)
   376  		assert.Equal(t, res.Result, []interface{}{7})
   377  	}
   378  }
   379  
   380  func TestMethodsValidityOnNonPtr(t *testing.T) {
   381  	t.Parallel()
   382  	obj := New(CustomType(1))
   383  
   384  	assert.False(t, obj.IsPtr())
   385  
   386  	assert.True(t, obj.Method("Method1").IsValid())
   387  	// False because it's not a pointer
   388  	assert.False(t, obj.Method("Method2").IsValid())
   389  
   390  	{
   391  		res, err := obj.Method("Method1").Call()
   392  		assert.Nil(t, err)
   393  		assert.Equal(t, res.Result, []interface{}{"yep"})
   394  	}
   395  	{
   396  		_, err := obj.Method("Method2").Call()
   397  		assert.NotNil(t, err)
   398  	}
   399  }
   400  
   401  func testCallMethod(t *testing.T, callValue bool, lenResult int) bool {
   402  	obj := New(&Person{})
   403  	res, err := obj.Method("ReturnsError").Call(callValue)
   404  	assert.Nil(t, err)
   405  	assert.Equal(t, len(res.Result), lenResult)
   406  	return res.IsError()
   407  }
   408  
   409  func TestCallMethodWithoutErrResult(t *testing.T) {
   410  	t.Parallel()
   411  	isErr := testCallMethod(t, true, 3)
   412  	assert.True(t, isErr)
   413  }
   414  
   415  func TestCallMethodWithErrResult(t *testing.T) {
   416  	t.Parallel()
   417  	isErr := testCallMethod(t, false, 3)
   418  	assert.False(t, isErr)
   419  }
   420  
   421  func TestTag(t *testing.T) {
   422  	t.Parallel()
   423  	obj := New(&Person{})
   424  	tag, err := obj.Field("Street").Tag("invalid")
   425  	assert.Nil(t, err)
   426  	assert.Equal(t, len(tag), 0)
   427  }
   428  
   429  func TestInvalidTag(t *testing.T) {
   430  	t.Parallel()
   431  	obj := New(&Person{})
   432  	tag, err := obj.Field("HahaStreet").Tag("invalid")
   433  	assert.NotNil(t, err)
   434  	assert.Equal(t, "invalid field HahaStreet", err.Error())
   435  	assert.Equal(t, len(tag), 0)
   436  }
   437  
   438  func TestValidTag(t *testing.T) {
   439  	t.Parallel()
   440  	obj := New(&Person{})
   441  	tag, err := obj.Field("Street").Tag("tag")
   442  	assert.Nil(t, err)
   443  	assert.Equal(t, tag, "be")
   444  }
   445  
   446  func TestValidTags(t *testing.T) {
   447  	t.Parallel()
   448  	obj := New(&Person{})
   449  
   450  	tags, err := obj.Field("Street").TagExpanded("tag")
   451  	assert.Nil(t, err)
   452  	assert.Equal(t, tags, []string{"be"})
   453  
   454  	tags2, err := obj.Field("Street").TagExpanded("tag2")
   455  	assert.Nil(t, err)
   456  	assert.Equal(t, tags2, []string{"1", "2", "3"})
   457  }
   458  
   459  func TestAllTags(t *testing.T) {
   460  	t.Parallel()
   461  	obj := New(&Person{})
   462  
   463  	tags, err := obj.Field("Street").Tags()
   464  	assert.Nil(t, err)
   465  	assert.Equal(t, len(tags), 2)
   466  	assert.Equal(t, tags["tag"].Value, "be")
   467  	assert.Equal(t, tags["tag2"].Value, "1,2,3")
   468  }
   469  
   470  func TestNewFromType(t *testing.T) {
   471  	t.Parallel()
   472  	obj1 := NewFromType(reflect.TypeOf(Person{}))
   473  	obj2 := New(&Person{})
   474  
   475  	assert.Equal(t, obj1.objType.String(), obj2.objType.String())
   476  	assert.Equal(t, obj1.objKind.String(), obj2.objKind.String())
   477  	assert.Equal(t, obj1.underlyingType.String(), obj2.underlyingType.String())
   478  }
   479  
   480  func TestAnonymousFields(t *testing.T) {
   481  	t.Parallel()
   482  	obj := New(&Person{})
   483  
   484  	assert.True(t, obj.Field("Address").IsAnonymous())
   485  	assert.False(t, obj.Field("Name").IsAnonymous())
   486  }
   487  
   488  func TestNil(t *testing.T) {
   489  	t.Parallel()
   490  	obj := New(nil)
   491  	assert.Equal(t, 0, len(obj.Fields()))
   492  	assert.Equal(t, 0, len(obj.Methods()))
   493  
   494  	res, err := obj.Field("Aaa").Get()
   495  	assert.Nil(t, res)
   496  	assert.NotNil(t, err)
   497  
   498  	err = obj.Field("Aaa").Set(1)
   499  	assert.NotNil(t, err)
   500  }
   501  
   502  func TestNilType(t *testing.T) {
   503  	t.Parallel()
   504  	obj := NewFromType(nil)
   505  	assert.Equal(t, 0, len(obj.Fields()))
   506  	assert.Equal(t, 0, len(obj.Methods()))
   507  
   508  	res, err := obj.Field("Aaa").Get()
   509  	assert.Nil(t, res)
   510  	assert.NotNil(t, err)
   511  
   512  	err = obj.Field("Aaa").Set(1)
   513  	assert.NotNil(t, err)
   514  
   515  	_, err = obj.Method("aaa").Call("bu")
   516  	assert.NotNil(t, err)
   517  }
   518  
   519  func TestStringObj(t *testing.T) {
   520  	t.Parallel()
   521  	obj := New("")
   522  	assert.Equal(t, 0, len(obj.Fields()))
   523  	assert.Equal(t, 0, len(obj.Methods()))
   524  
   525  	res, err := obj.Field("Aaa").Get()
   526  	assert.Nil(t, res)
   527  	assert.NotNil(t, err)
   528  
   529  	err = obj.Field("Aaa").Set(1)
   530  	assert.NotNil(t, err)
   531  
   532  	_, err = obj.Method("aaa").Call("bu")
   533  	assert.NotNil(t, err)
   534  }
   535  
   536  type TestWithInnerStruct struct {
   537  	Aaa string
   538  	Bbb struct {
   539  		Ccc int
   540  		Ddd float64
   541  	}
   542  }
   543  
   544  func TestInnerStruct(t *testing.T) {
   545  	t.Parallel()
   546  	obj := New(TestWithInnerStruct{})
   547  	fields := obj.Fields()
   548  	assert.Equal(t, 2, len(fields))
   549  
   550  	assert.Equal(t, "Aaa", fields[0].Name())
   551  	assert.Equal(t, "string", fields[0].Type().String())
   552  	assert.Equal(t, "string", fields[0].Kind().String())
   553  
   554  	assert.Equal(t, "Bbb", fields[1].Name())
   555  	assert.Equal(t, "struct { Ccc int; Ddd float64 }", fields[1].Type().String())
   556  	assert.Equal(t, "struct", fields[1].Kind().String())
   557  
   558  	// This is not an anonymous struct, so fields are always the same:
   559  	assert.Equal(t, 2, len(obj.FieldsAll()))
   560  	assert.Equal(t, 2, len(obj.FieldsFlattened()))
   561  }
   562  
   563  func TestExportedUnexported(t *testing.T) {
   564  	t.Parallel()
   565  	obj := New(&TestStruct{})
   566  	assert.Equal(t, "_", obj.Fields()[0].Name())
   567  	assert.False(t, obj.Fields()[0].IsExported())
   568  
   569  	assert.Equal(t, "Exported", obj.Fields()[1].Name())
   570  	assert.True(t, obj.Fields()[1].IsExported())
   571  
   572  	assert.Equal(t, "unexported", obj.Fields()[2].Name())
   573  	assert.False(t, obj.Fields()[2].IsExported())
   574  
   575  	err := obj.Field("Exported").Set("aaa")
   576  	assert.Nil(t, err)
   577  
   578  	err = obj.Field("unexported").Set(1777)
   579  	assert.NotNil(t, err)
   580  	assert.Contains(t, err.Error(), "not settable")
   581  
   582  	value, err := obj.Field("unexported").Get()
   583  	assert.NotNil(t, err)
   584  	assert.Nil(t, value)
   585  	assert.Contains(t, err.Error(), "cannot read unexported field")
   586  
   587  	// But tags on unexported fields are still readable:
   588  	{
   589  		tags, err := obj.Field("_").Tags()
   590  		assert.Nil(t, err)
   591  		assert.Equal(t, 1, len(tags))
   592  		assert.Equal(t, "ba", tags["bu"].Value)
   593  	}
   594  	{
   595  		tags, err := obj.Field("unexported").Tags()
   596  		assert.Nil(t, err)
   597  		assert.Equal(t, 2, len(tags))
   598  	}
   599  }
   600  
   601  func TestStringLen(t *testing.T) {
   602  	s := "jkljk"
   603  	assert.Equal(t, len(s), New(s).Len())
   604  	assert.Equal(t, len(s), New(&s).Len())
   605  }
   606  
   607  func TestLenOfInvalidTypes(t *testing.T) {
   608  	assert.Equal(t, 0, New(&TestStruct{}).Len())
   609  	assert.Equal(t, 0, New(TestStruct{}).Len())
   610  
   611  	{
   612  		val, found := New(TestStruct{}).GetByIndex(20)
   613  		assert.False(t, found)
   614  		assert.Nil(t, val)
   615  	}
   616  	{
   617  		val, found := New(TestStruct{}).GetByKey("nothing")
   618  		assert.False(t, found)
   619  		assert.Equal(t, nil, val)
   620  	}
   621  	{
   622  		keys, err := New(TestStruct{}).Keys()
   623  		assert.Nil(t, keys)
   624  		assert.NotNil(t, err)
   625  	}
   626  }
   627  
   628  func TestSlice(t *testing.T) {
   629  	{
   630  		a := []int{1, 2, 3, 4, 8, 7, 6, 5}
   631  		assert.Equal(t, len(a), New(a).Len())
   632  		assert.Equal(t, len(a), New(&a).Len())
   633  		{
   634  			o := New(&a)
   635  			assert.Nil(t, o.SetByIndex(1, 1000))
   636  			assert.Equal(t, []int{1, 1000, 3, 4, 8, 7, 6, 5}, a)
   637  		}
   638  		{
   639  			o := New(&a)
   640  			assert.NotNil(t, o.SetByIndex(-1, 1000))
   641  			assert.NotNil(t, o.SetByIndex(700, 1000))
   642  		}
   643  		{
   644  			o := New(a)
   645  			assert.Nil(t, o.SetByIndex(1, 1000))
   646  			assert.Equal(t, []int{1, 1000, 3, 4, 8, 7, 6, 5}, a)
   647  		}
   648  		{
   649  			val, found := New(a).GetByIndex(2)
   650  			assert.True(t, found)
   651  			assert.Equal(t, val, 3)
   652  		}
   653  		{
   654  			val, found := New(a).GetByIndex(20)
   655  			assert.False(t, found)
   656  			assert.Nil(t, val)
   657  		}
   658  		{
   659  			val, found := New(a).GetByIndex(-20)
   660  			assert.False(t, found)
   661  			assert.Nil(t, val)
   662  		}
   663  	}
   664  }
   665  
   666  func TestMapLenGetSet(t *testing.T) {
   667  	m := map[string]interface{}{"jkljk": 8, "11": 13, "12": nil}
   668  	assert.Equal(t, len(m), New(m).Len())
   669  	assert.Equal(t, len(m), New(&m).Len())
   670  	{
   671  		keys, err := New(&m).Keys()
   672  		assert.Nil(t, err)
   673  		assert.Equal(t, 3, len(keys))
   674  		keysStrings := make([]string, len(keys))
   675  		for n := range keys {
   676  			keysStrings[n] = keys[n].(string)
   677  		}
   678  		sort.Strings(keysStrings)
   679  		assert.Equal(t, []string{"11", "12", "jkljk"}, keysStrings)
   680  	}
   681  	{
   682  		val, found := New(&m).GetByKey("11")
   683  		assert.True(t, found)
   684  		assert.Equal(t, 13, val)
   685  	}
   686  	{
   687  		val, found := New(m).GetByKey("11")
   688  		assert.True(t, found)
   689  		assert.Equal(t, 13, val)
   690  	}
   691  	{
   692  		val, found := New(m).GetByKey("12")
   693  		assert.True(t, found)
   694  		assert.Equal(t, nil, val)
   695  	}
   696  	{
   697  		val, found := New(m).GetByKey("nothing")
   698  		assert.False(t, found)
   699  		assert.Equal(t, nil, val)
   700  	}
   701  	{
   702  		val, found := New(m).GetByKey(17)
   703  		assert.False(t, found)
   704  		assert.Equal(t, nil, val)
   705  	}
   706  }
   707  
   708  func TestMapSet(t *testing.T) {
   709  	m := map[string]interface{}{"jkljk": 8, "11": 13, "12": nil}
   710  	o := New(&m)
   711  	assert.Nil(t, o.SetByKey("17", 71))
   712  	val, found := m["17"]
   713  	assert.True(t, found)
   714  	assert.Equal(t, 71, val)
   715  }
   716  
   717  func TestSetStringByIndex(t *testing.T) {
   718  	s := "jkljkl"
   719  	o := New(&s)
   720  	assert.NotNil(t, o.SetByIndex(0, 'a'))
   721  }