github.com/ugorji/go/codec@v1.2.13-0.20240307214044-07c54c229a5a/values_flex_test.go (about)

     1  // comment this out // // + build testing
     2  
     3  // Copyright (c) 2012-2020 Ugorji Nwoke. All rights reserved.
     4  // Use of this source code is governed by a MIT license found in the LICENSE file.
     5  
     6  package codec
     7  
     8  import (
     9  	"fmt"
    10  	"strconv"
    11  	"strings"
    12  	"time"
    13  )
    14  
    15  const teststrucflexChanCap = 64
    16  
    17  // This file contains values used by tests alone.
    18  // This is where we may try out different things,
    19  // that other engines may not support or may barf upon
    20  // e.g. custom extensions for wrapped types, maps with non-string keys, etc.
    21  
    22  // some funky types to test codecgen
    23  
    24  type codecgenA struct {
    25  	ZZ []byte
    26  }
    27  type codecgenB struct {
    28  	AA codecgenA
    29  }
    30  type codecgenC struct {
    31  	_struct struct{} `codec:",omitempty"`
    32  	BB      codecgenB
    33  }
    34  
    35  type TestCodecgenG struct {
    36  	TestCodecgenG int
    37  }
    38  type codecgenH struct {
    39  	TestCodecgenG
    40  }
    41  type codecgenI struct {
    42  	codecgenH
    43  }
    44  
    45  type codecgenK struct {
    46  	X int
    47  	Y string
    48  }
    49  type codecgenL struct {
    50  	X int
    51  	Y uint32
    52  }
    53  type codecgenM struct {
    54  	codecgenK
    55  	codecgenL
    56  }
    57  
    58  // some types to test struct keytype
    59  
    60  type testStrucKeyTypeT0 struct {
    61  	_struct struct{}
    62  	F       int
    63  }
    64  type testStrucKeyTypeT1 struct {
    65  	_struct struct{} `codec:",string"`
    66  	F       int      `codec:"FFFF"`
    67  }
    68  type testStrucKeyTypeT2 struct {
    69  	_struct struct{} `codec:",int"`
    70  	F       int      `codec:"-1"`
    71  }
    72  type testStrucKeyTypeT3 struct {
    73  	_struct struct{} `codec:",uint"`
    74  	F       int      `codec:"1"`
    75  }
    76  type testStrucKeyTypeT4 struct {
    77  	_struct struct{} `codec:",float"`
    78  	F       int      `codec:"2.5"`
    79  }
    80  
    81  // Some unused types just stored here
    82  
    83  type Bbool bool
    84  type Aarray [1]string
    85  type Sstring string
    86  type Sstructsmall struct {
    87  	A int
    88  }
    89  
    90  type Sstructbig struct {
    91  	_struct struct{}
    92  	A       int
    93  	B       bool
    94  	c       string
    95  	// Sval Sstruct
    96  	Ssmallptr *Sstructsmall
    97  	Ssmall    Sstructsmall
    98  	Sptr      *Sstructbig
    99  }
   100  
   101  type SstructbigToArray struct {
   102  	_struct struct{} `codec:",toarray"`
   103  	A       int
   104  	B       bool
   105  	c       string
   106  	// Sval Sstruct
   107  	Ssmallptr *Sstructsmall
   108  	Ssmall    Sstructsmall
   109  	Sptr      *Sstructbig
   110  }
   111  
   112  // small struct for testing that codecgen works for unexported types
   113  type tLowerFirstLetter struct {
   114  	I int
   115  	u uint64
   116  	S string
   117  	b []byte
   118  }
   119  
   120  // Some wrapped types which are used as extensions
   121  type wrapInt64 int64
   122  type wrapUint8 uint8
   123  type wrapBytes []byte
   124  
   125  // some types that define how to marshal themselves
   126  type testMarshalAsJSON bool
   127  type testMarshalAsBinary []byte
   128  type testMarshalAsText string
   129  
   130  // some types used for extensions
   131  type testUintToBytes uint32
   132  
   133  func (x testMarshalAsJSON) MarshalJSON() (data []byte, err error) {
   134  	if x {
   135  		data = []byte("true")
   136  	} else {
   137  		data = []byte("false")
   138  	}
   139  	return
   140  }
   141  func (x *testMarshalAsJSON) UnmarshalJSON(data []byte) (err error) {
   142  	switch string(data) {
   143  	case "true":
   144  		*x = true
   145  	case "false":
   146  		*x = false
   147  	default:
   148  		err = fmt.Errorf("testMarshalAsJSON failed to decode as bool: %s", data)
   149  	}
   150  	return
   151  }
   152  
   153  func (x testMarshalAsBinary) MarshalBinary() (data []byte, err error) {
   154  	data = []byte(x)
   155  	return
   156  }
   157  func (x *testMarshalAsBinary) UnmarshalBinary(data []byte) (err error) {
   158  	*x = data
   159  	return
   160  }
   161  
   162  func (x testMarshalAsText) MarshalText() (text []byte, err error) {
   163  	text = []byte(x)
   164  	return
   165  }
   166  func (x *testMarshalAsText) UnmarshalText(text []byte) (err error) {
   167  	*x = testMarshalAsText(string(text))
   168  	return
   169  }
   170  
   171  type AnonInTestStrucIntf struct {
   172  	Islice []interface{}
   173  	Ms     map[string]interface{}
   174  	Nintf  interface{} //don't set this, so we can test for nil
   175  	T      time.Time
   176  	Tptr   *time.Time
   177  }
   178  
   179  type missingFielderT1 struct {
   180  	S string
   181  	B bool
   182  	f float64
   183  	i int64
   184  }
   185  
   186  func (t *missingFielderT1) CodecMissingField(field []byte, value interface{}) bool {
   187  	switch string(field) {
   188  	case "F":
   189  		t.f = value.(float64)
   190  	case "I":
   191  		t.i = value.(int64)
   192  	default:
   193  		return false
   194  	}
   195  	return true
   196  }
   197  
   198  func (t *missingFielderT1) CodecMissingFields() map[string]interface{} {
   199  	return map[string]interface{}{"F": t.f, "I": t.i}
   200  }
   201  
   202  type missingFielderT11 struct {
   203  	s1 string
   204  	S2 string
   205  }
   206  
   207  func (t *missingFielderT11) CodecMissingField(field []byte, value interface{}) bool {
   208  	if "s1" == string(field) {
   209  		t.s1 = value.(string)
   210  		return true
   211  	}
   212  	return false
   213  }
   214  
   215  // missingFielderT11 implements CodecMissingFields on the value (not pointer)
   216  func (t missingFielderT11) CodecMissingFields() map[string]interface{} {
   217  	return map[string]interface{}{"s1": t.s1}
   218  }
   219  
   220  type missingFielderT2 struct {
   221  	S string
   222  	B bool
   223  	F float64
   224  	I int64
   225  }
   226  
   227  type testSelfExtHelper struct {
   228  	S string
   229  	I int64
   230  	B bool
   231  }
   232  
   233  type TestSelfExtImpl struct {
   234  	testSelfExtHelper
   235  }
   236  
   237  type TestSelfExtImpl2 struct {
   238  	M string
   239  	O bool
   240  }
   241  
   242  type TestTwoNakedInterfaces struct {
   243  	A interface{}
   244  	B interface{}
   245  }
   246  
   247  var testWRepeated512 wrapBytes
   248  var testStrucTime = time.Date(2012, 2, 2, 2, 2, 2, 2000, time.UTC).UTC()
   249  
   250  func init() {
   251  	var testARepeated512 [512]byte
   252  	for i := range testARepeated512 {
   253  		testARepeated512[i] = 'A'
   254  	}
   255  	testWRepeated512 = wrapBytes(testARepeated512[:])
   256  }
   257  
   258  type TestStrucFlex struct {
   259  	_struct struct{} `codec:",omitempty"` //set omitempty for every field
   260  	TestStrucCommon
   261  
   262  	Chstr chan string
   263  
   264  	Mis     map[int]string
   265  	Mbu64   map[bool]struct{}
   266  	Mu8e    map[byte]struct{}
   267  	Mu8u64  map[byte]stringUint64T
   268  	Msp2ss  map[*string][]string
   269  	Mip2ss  map[*uint64][]string
   270  	Ms2misu map[string]map[uint64]stringUint64T
   271  	Miwu64s map[int]wrapUint64Slice
   272  	Mfwss   map[float64]wrapStringSlice
   273  	Mf32wss map[float32]wrapStringSlice
   274  	Mui2wss map[uint64]wrapStringSlice
   275  
   276  	// DecodeNaked bombs because stringUint64T is decoded as a map,
   277  	// and a map cannot be the key type of a map.
   278  	// Ensure this is set to nil if decoding into a nil interface{}.
   279  	Msu2wss map[stringUint64T]wrapStringSlice
   280  
   281  	Ci64       wrapInt64
   282  	Swrapbytes []wrapBytes
   283  	Swrapuint8 []wrapUint8
   284  
   285  	ArrStrUi64T [4]stringUint64T
   286  
   287  	Ui64array      [4]uint64
   288  	Ui64slicearray []*[4]uint64
   289  
   290  	SintfAarray []interface{}
   291  
   292  	// Ensure this is set to nil if decoding into a nil interface{}.
   293  	MstrUi64TSelf map[stringUint64T]*stringUint64T
   294  
   295  	Ttime    time.Time
   296  	Ttimeptr *time.Time
   297  
   298  	// make this a ptr, so that it could be set or not.
   299  	// for comparison (e.g. with msgp), give it a struct tag (so it is not inlined),
   300  	// make this one omitempty (so it is excluded if nil).
   301  	*AnonInTestStrucIntf `json:",omitempty"`
   302  
   303  	M          map[interface{}]interface{} `json:"-"`
   304  	Msu        map[wrapString]interface{}
   305  	Mtsptr     map[string]*TestStrucFlex
   306  	Mts        map[string]TestStrucFlex
   307  	Its        []*TestStrucFlex
   308  	Nteststruc *TestStrucFlex
   309  
   310  	MarJ testMarshalAsJSON
   311  	MarT testMarshalAsText
   312  	MarB testMarshalAsBinary
   313  
   314  	XuintToBytes testUintToBytes
   315  
   316  	Ffunc       func() error // expect this to be skipped/ignored
   317  	Bboolignore bool         `codec:"-"` // expect this to be skipped/ignored
   318  
   319  	Cmplx64  complex64
   320  	Cmplx128 complex128
   321  }
   322  
   323  func newTestStrucFlex(depth, n int, bench, useInterface, useStringKeyOnly bool) (ts *TestStrucFlex) {
   324  	ts = &TestStrucFlex{
   325  		Chstr: make(chan string, teststrucflexChanCap),
   326  
   327  		Miwu64s: map[int]wrapUint64Slice{
   328  			5: []wrapUint64{1, 2, 3, 4, 5},
   329  			3: []wrapUint64{1, 2, 3},
   330  		},
   331  
   332  		Mf32wss: map[float32]wrapStringSlice{
   333  			5.0: []wrapString{"1.0", "2.0", "3.0", "4.0", "5.0"},
   334  			3.0: []wrapString{"1.0", "2.0", "3.0"},
   335  		},
   336  
   337  		Mui2wss: map[uint64]wrapStringSlice{
   338  			5: []wrapString{"1.0", "2.0", "3.0", "4.0", "5.0"},
   339  			3: []wrapString{"1.0", "2.0", "3.0"},
   340  		},
   341  
   342  		Mfwss: map[float64]wrapStringSlice{
   343  			5.0: []wrapString{"1.0", "2.0", "3.0", "4.0", "5.0"},
   344  			3.0: []wrapString{"1.0", "2.0", "3.0"},
   345  		},
   346  
   347  		// DecodeNaked bombs here, because the stringUint64T is decoded as a map,
   348  		// and a map cannot be the key type of a map.
   349  		// Ensure this is set to nil if decoding into a nil interface{}.
   350  		Msu2wss: map[stringUint64T]wrapStringSlice{
   351  			stringUint64T{"5", 5}: []wrapString{"1", "2", "3", "4", "5"},
   352  			stringUint64T{"3", 3}: []wrapString{"1", "2", "3"},
   353  		},
   354  
   355  		Mis: map[int]string{
   356  			1:   "one",
   357  			22:  "twenty two",
   358  			-44: "minus forty four",
   359  		},
   360  
   361  		Ms2misu: map[string]map[uint64]stringUint64T{
   362  			"1":   {1: {"11", 11}},
   363  			"22":  {1: {"2222", 2222}},
   364  			"333": {1: {"333333", 333333}},
   365  		},
   366  
   367  		Mbu64:  map[bool]struct{}{false: {}, true: {}},
   368  		Mu8e:   map[byte]struct{}{1: {}, 2: {}, 3: {}, 4: {}},
   369  		Mu8u64: make(map[byte]stringUint64T),
   370  		Mip2ss: make(map[*uint64][]string),
   371  		Msp2ss: make(map[*string][]string),
   372  		M:      make(map[interface{}]interface{}),
   373  		Msu:    make(map[wrapString]interface{}),
   374  
   375  		Ci64: -22,
   376  		Swrapbytes: []wrapBytes{ // lengths of 1, 2, 4, 8, 16, 32, 64, 128, 256,
   377  			testWRepeated512[:1],
   378  			testWRepeated512[:2],
   379  			testWRepeated512[:4],
   380  			testWRepeated512[:8],
   381  			testWRepeated512[:16],
   382  			testWRepeated512[:32],
   383  			testWRepeated512[:64],
   384  			testWRepeated512[:128],
   385  			testWRepeated512[:256],
   386  			testWRepeated512[:512],
   387  		},
   388  		Swrapuint8: []wrapUint8{
   389  			'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
   390  		},
   391  		Ui64array:     [4]uint64{4, 16, 64, 256},
   392  		ArrStrUi64T:   [4]stringUint64T{{"4", 4}, {"3", 3}, {"2", 2}, {"1", 1}},
   393  		SintfAarray:   []interface{}{Aarray{"s"}},
   394  		MstrUi64TSelf: make(map[stringUint64T]*stringUint64T, numStrUi64T),
   395  
   396  		Ttime:    testStrucTime,
   397  		Ttimeptr: &testStrucTime,
   398  
   399  		MarJ: true,
   400  		MarT: "hello string",
   401  		MarB: []byte("hello bytes"),
   402  
   403  		XuintToBytes: 16,
   404  
   405  		Cmplx64:  complex(16, 0),
   406  		Cmplx128: complex(1616, 0),
   407  	}
   408  
   409  	var strslice []string
   410  	for i := uint64(0); i < numStrUi64T; i++ {
   411  		s := strings.Repeat(strconv.FormatUint(i, 10), 4)
   412  		ss := stringUint64T{S: s, U: i}
   413  		strslice = append(strslice, s)
   414  		// Ensure this is set to nil if decoding into a nil interface{}.
   415  		ts.MstrUi64TSelf[ss] = &ss
   416  		ts.Mu8u64[s[0]] = ss
   417  		ts.Mip2ss[&i] = strslice
   418  		ts.Msp2ss[&s] = strslice
   419  		// add some other values of maps and pointers into M
   420  		ts.M[s] = strslice
   421  		// cannot use this, as converting stringUint64T to interface{} returns map,
   422  		// DecodeNaked does this, causing "hash of unhashable value" as some maps cannot be map keys
   423  		// ts.M[ss] = &ss
   424  		ts.Msu[wrapString(s)] = &ss
   425  		s = s + "-map"
   426  		ss.S = s
   427  		ts.M[s] = map[string]string{s: s}
   428  		ts.Msu[wrapString(s)] = map[string]string{s: s}
   429  	}
   430  
   431  	numChanSend := cap(ts.Chstr) / 4 // 8
   432  	for i := 0; i < numChanSend; i++ {
   433  		ts.Chstr <- strings.Repeat("A", i+1)
   434  	}
   435  
   436  	ts.Ui64slicearray = []*[4]uint64{&ts.Ui64array, &ts.Ui64array}
   437  
   438  	if useInterface {
   439  		ts.AnonInTestStrucIntf = &AnonInTestStrucIntf{
   440  			Islice: []interface{}{strRpt(n, "true"), true, strRpt(n, "no"), false, uint64(288), float64(0.4)},
   441  			Ms: map[string]interface{}{
   442  				strRpt(n, "true"):     strRpt(n, "true"),
   443  				strRpt(n, "int64(9)"): false,
   444  			},
   445  			T:    testStrucTime,
   446  			Tptr: &testStrucTime,
   447  		}
   448  	}
   449  
   450  	populateTestStrucCommon(&ts.TestStrucCommon, n, bench, useInterface, useStringKeyOnly)
   451  	if depth > 0 {
   452  		depth--
   453  		if ts.Mtsptr == nil {
   454  			ts.Mtsptr = make(map[string]*TestStrucFlex)
   455  		}
   456  		if ts.Mts == nil {
   457  			ts.Mts = make(map[string]TestStrucFlex)
   458  		}
   459  		ts.Mtsptr["0"] = newTestStrucFlex(depth, n, bench, useInterface, useStringKeyOnly)
   460  		ts.Mts["0"] = *(ts.Mtsptr["0"])
   461  		ts.Its = append(ts.Its, ts.Mtsptr["0"])
   462  	}
   463  	return
   464  }