github.com/ugorji/go/codec@v1.2.13-0.20240307214044-07c54c229a5a/values_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  // This file contains values used by tests and benchmarks.
     9  // The benchmarks will test performance against other libraries
    10  // (encoding/json, json-iterator, bson, gob, etc).
    11  // Consequently, we only use values that will parse well in all engines,
    12  // and only leverage features that work across multiple libraries for a truer comparison.
    13  // For example,
    14  // - JSON/BSON do not like maps with keys that are not strings,
    15  //   so we only use maps with string keys here.
    16  // - _struct options are not honored by other libraries,
    17  //   so we don't use them in this file.
    18  
    19  import (
    20  	"math"
    21  	"strconv"
    22  	"strings"
    23  )
    24  
    25  // func init() {
    26  // 	rt := reflect.TypeOf((*TestStruc)(nil)).Elem()
    27  // 	defTypeInfos.get(rt2id(rt), rt)
    28  // }
    29  
    30  const numStrUi64T = 32 // use 8, prefer 32, test with 1024
    31  
    32  type wrapSliceUint64 []uint64
    33  type wrapSliceString []string
    34  type wrapUint64 uint64
    35  type wrapString string
    36  type wrapUint64Slice []wrapUint64
    37  type wrapStringSlice []wrapString
    38  
    39  // some other types
    40  
    41  type stringUint64T struct {
    42  	S string
    43  	U uint64
    44  }
    45  
    46  type AnonInTestStrucSlim struct {
    47  	S string
    48  	P *string
    49  }
    50  
    51  type AnonInTestStruc struct {
    52  	AS         string
    53  	AI64       int64
    54  	AI16       int16
    55  	AUi64      uint64
    56  	ASslice    []string
    57  	AI64slice  []int64
    58  	AUi64slice []uint64
    59  	AF64slice  []float64
    60  	AF32slice  []float32
    61  
    62  	AMSS map[string]string
    63  	// AMI32U32  map[int32]uint32
    64  	// AMU32F64 map[uint32]float64 // json/bson do not like it
    65  	AMSU64 map[string]uint64
    66  
    67  	AI64arr8 [8]int64
    68  
    69  	// use these to test 0-len or nil slices/maps/arrays
    70  	AI64arr0    [0]int64
    71  	AI64slice0  []int64
    72  	AUi64sliceN []uint64
    73  	AMSU64N     map[string]uint64
    74  	AMSU64E     map[string]uint64
    75  }
    76  
    77  // testSimpleFields is a sub-set of TestStrucCommon
    78  type testSimpleFields struct {
    79  	S string
    80  
    81  	I64 int64
    82  	I8  int8
    83  
    84  	Ui64 uint64
    85  	Ui8  uint8
    86  
    87  	F64 float64
    88  	F32 float32
    89  
    90  	B bool
    91  
    92  	Sslice    []string
    93  	I32slice  []int32
    94  	Ui64slice []uint64
    95  	Ui8slice  []uint8
    96  	Bslice    []bool
    97  
    98  	Iptrslice []*int64
    99  
   100  	WrapSliceInt64  wrapSliceUint64
   101  	WrapSliceString wrapSliceString
   102  
   103  	Msint map[string]int
   104  }
   105  
   106  type TestStrucCommon struct {
   107  	S string
   108  
   109  	I64 int64
   110  	I32 int32
   111  	I16 int16
   112  	I8  int8
   113  
   114  	I64n int64
   115  	I32n int32
   116  	I16n int16
   117  	I8n  int8
   118  
   119  	Ui64 uint64
   120  	Ui32 uint32
   121  	Ui16 uint16
   122  	Ui8  uint8
   123  
   124  	F64 float64
   125  	F32 float32
   126  
   127  	B  bool
   128  	By uint8 // byte: msgp doesn't like byte
   129  
   130  	Sslice    []string
   131  	I64slice  []int64
   132  	I32slice  []int32
   133  	Ui64slice []uint64
   134  	Ui8slice  []uint8
   135  	Bslice    []bool
   136  	Byslice   []byte
   137  
   138  	BytesSlice [][]byte
   139  
   140  	Iptrslice []*int64
   141  
   142  	WrapSliceInt64  wrapSliceUint64
   143  	WrapSliceString wrapSliceString
   144  
   145  	Msint map[string]int
   146  
   147  	Msbytes map[string][]byte
   148  
   149  	Simplef testSimpleFields
   150  
   151  	SstrUi64T []stringUint64T
   152  	MstrUi64T map[string]*stringUint64T
   153  
   154  	AnonInTestStruc
   155  
   156  	NotAnon AnonInTestStruc
   157  
   158  	*AnonInTestStrucSlim
   159  	NotAnonSlim *AnonInTestStrucSlim
   160  
   161  	// R          Raw // Testing Raw must be explicitly turned on, so use standalone test
   162  	// Rext RawExt // Testing RawExt is tricky, so use standalone test
   163  
   164  	Nmap   map[string]bool //don't set this, so we can test for nil
   165  	Nslice []byte          //don't set this, so we can test for nil
   166  	Nint64 *int64          //don't set this, so we can test for nil
   167  }
   168  
   169  type TestStruc struct {
   170  	// _struct struct{} `json:",omitempty"` //set omitempty for every field
   171  
   172  	TestStrucCommon
   173  
   174  	Mtsptr     map[string]*TestStruc
   175  	Mts        map[string]TestStruc
   176  	Its        []*TestStruc
   177  	Nteststruc *TestStruc
   178  }
   179  
   180  func populateTestStrucCommon(ts *TestStrucCommon, n int, bench, useInterface, useStringKeyOnly bool) {
   181  	var i64a, i64b, i64c, i64d int64 = 64, 6464, 646464, 64646464
   182  
   183  	// if bench, do not use uint64 values > math.MaxInt64, as bson, etc cannot decode them
   184  
   185  	var a = AnonInTestStruc{
   186  		// There's more leeway in altering this.
   187  		AS:    strRpt(n, "A-String"),
   188  		AI64:  -64646464,
   189  		AI16:  1616,
   190  		AUi64: 64646464,
   191  		// (U+1D11E)G-clef character may be represented in json as "\uD834\uDD1E".
   192  		// single reverse solidus character may be represented in json as "\u005C".
   193  		// include these in ASslice below.
   194  		ASslice: []string{
   195  			strRpt(n, "Aone"),
   196  			strRpt(n, "Atwo"),
   197  			strRpt(n, "Athree"),
   198  			strRpt(n, "Afour.reverse_solidus.\u005c"),
   199  			strRpt(n, "Afive.Gclef.\U0001d11E\"ugorji\"done.")},
   200  		AI64slice: []int64{
   201  			0, 1, -1, -22, 333, -4444, 55555, -666666,
   202  			// msgpack ones
   203  			-48, -32, -24, -8, 32, 127, 192, 255,
   204  			// standard ones
   205  			0, -1, 1,
   206  			math.MaxInt8, math.MaxInt8 + 4, math.MaxInt8 - 4,
   207  			math.MaxInt16, math.MaxInt16 + 4, math.MaxInt16 - 4,
   208  			math.MaxInt32, math.MaxInt32 + 4, math.MaxInt32 - 4,
   209  			math.MaxInt64, math.MaxInt64 - 4,
   210  			math.MinInt8, math.MinInt8 + 4, math.MinInt8 - 4,
   211  			math.MinInt16, math.MinInt16 + 4, math.MinInt16 - 4,
   212  			math.MinInt32, math.MinInt32 + 4, math.MinInt32 - 4,
   213  			math.MinInt64, math.MinInt64 + 4,
   214  		},
   215  		AUi64slice: []uint64{
   216  			0, 1, 22, 333, 4444, 55555, 666666,
   217  			// standard ones
   218  			math.MaxUint8, math.MaxUint8 + 4, math.MaxUint8 - 4,
   219  			math.MaxUint16, math.MaxUint16 + 4, math.MaxUint16 - 4,
   220  			math.MaxUint32, math.MaxUint32 + 4, math.MaxUint32 - 4,
   221  		},
   222  		AMSU64: map[string]uint64{
   223  			strRpt(n, "1"):    1,
   224  			strRpt(n, "22"):   2,
   225  			strRpt(n, "333"):  3,
   226  			strRpt(n, "4444"): 4,
   227  		},
   228  		AMSS: map[string]string{
   229  			strRpt(n, "1"):    strRpt(n, "1"),
   230  			strRpt(n, "22"):   strRpt(n, "22"),
   231  			strRpt(n, "333"):  strRpt(n, "333"),
   232  			strRpt(n, "4444"): strRpt(n, "4444"),
   233  		},
   234  
   235  		AI64arr8: [...]int64{1, 8, 2, 7, 3, 6, 4, 5},
   236  
   237  		// Note: +/- inf, NaN, and other non-representable numbers should not be explicitly tested here
   238  
   239  		AF64slice: []float64{
   240  			11.11e-11, -11.11e+11,
   241  			2.222e+12, -2.222e-12,
   242  			-555.55e-5, 555.55e+5,
   243  			666.66e-6, -666.66e+6,
   244  			7777.7777e-7, -7777.7777e-7,
   245  			-8888.8888e+8, 8888.8888e+8,
   246  			-99999.9999e+9, 99999.9999e+9,
   247  			// these below are hairy enough to need strconv.ParseFloat
   248  			33.33e-33, -33.33e+33,
   249  			44.44e+44, -44.44e-44,
   250  			// standard ones
   251  			0, -1, 1,
   252  			// math.Inf(1), math.Inf(-1),
   253  			math.Pi, math.Phi, math.E,
   254  			math.MaxFloat64, math.SmallestNonzeroFloat64,
   255  		},
   256  		AF32slice: []float32{
   257  			11.11e-1, -11.11e+1,
   258  			2.222e+2, -2.222e-2,
   259  			-55.55e-5, 55.55e+5,
   260  			66.66e-6, -66.66e+6,
   261  			777.777e-7, -777.777e-7,
   262  			-8.88e+8, 8.88e-8,
   263  			-99999.9999e+9, 99999.9999e+9,
   264  			// these below are hairy enough to need strconv.ParseFloat
   265  			33.33e-33, -33.33e+33,
   266  			// standard ones
   267  			0, -1, 1,
   268  			// math.Float32frombits(0x7FF00000), math.Float32frombits(0xFFF00000), //+inf and -inf
   269  			math.MaxFloat32, math.SmallestNonzeroFloat32,
   270  		},
   271  
   272  		AI64slice0:  []int64{},
   273  		AUi64sliceN: nil,
   274  		AMSU64N:     nil,
   275  		AMSU64E:     map[string]uint64{},
   276  	}
   277  
   278  	if !bench {
   279  		a.AUi64slice = append(a.AUi64slice, math.MaxUint64, math.MaxUint64-4)
   280  	}
   281  	*ts = TestStrucCommon{
   282  		S: strRpt(n, `some really really cool names that are nigerian and american like "ugorji melody nwoke" - get it? `),
   283  
   284  		// set the numbers close to the limits
   285  		I8:   math.MaxInt8 * 2 / 3,  // 8,
   286  		I8n:  math.MinInt8 * 2 / 3,  // 8,
   287  		I16:  math.MaxInt16 * 2 / 3, // 16,
   288  		I16n: math.MinInt16 * 2 / 3, // 16,
   289  		I32:  math.MaxInt32 * 2 / 3, // 32,
   290  		I32n: math.MinInt32 * 2 / 3, // 32,
   291  		I64:  math.MaxInt64 * 2 / 3, // 64,
   292  		I64n: math.MinInt64 * 2 / 3, // 64,
   293  
   294  		Ui64: math.MaxUint64 * 2 / 3, // 64
   295  		Ui32: math.MaxUint32 * 2 / 3, // 32
   296  		Ui16: math.MaxUint16 * 2 / 3, // 16
   297  		Ui8:  math.MaxUint8 * 2 / 3,  // 8
   298  
   299  		F32: 3.402823e+38, // max representable float32 without losing precision
   300  		F64: 3.40281991833838838338e+53,
   301  
   302  		B:  true,
   303  		By: 5,
   304  
   305  		Sslice:    []string{strRpt(n, "one"), strRpt(n, "two"), strRpt(n, "three")},
   306  		I64slice:  []int64{1111, 2222, 3333},
   307  		I32slice:  []int32{44, 55, 66},
   308  		Ui64slice: []uint64{12121212, 34343434, 56565656},
   309  		Ui8slice:  []uint8{210, 211, 212},
   310  		Bslice:    []bool{true, false, true, false},
   311  		Byslice:   []byte{13, 14, 15},
   312  		BytesSlice: [][]byte{
   313  			[]byte(strRpt(n, "one")),
   314  			[]byte(strRpt(n, "two")),
   315  			[]byte(strRpt(n, "\"three\"")),
   316  		},
   317  		Msint: map[string]int{
   318  			strRpt(n, "one"):       1,
   319  			strRpt(n, "two"):       2,
   320  			strRpt(n, "\"three\""): 3,
   321  		},
   322  		Msbytes: map[string][]byte{
   323  			strRpt(n, "one"):       []byte(strRpt(n, "one")),
   324  			strRpt(n, "two"):       []byte(strRpt(n, "two")),
   325  			strRpt(n, "\"three\""): []byte(strRpt(n, "\"three\"")),
   326  		},
   327  		WrapSliceInt64:  []uint64{4, 16, 64, 256},
   328  		WrapSliceString: []string{strRpt(n, "4"), strRpt(n, "16"), strRpt(n, "64"), strRpt(n, "256")},
   329  
   330  		// R: Raw([]byte("goodbye")),
   331  		// Rext: RawExt{ 120, []byte("hello"), }, // MARKER: don't set this - it's hard to test
   332  
   333  		// make Simplef same as top-level
   334  		// MARKER: should this have slightly different values???
   335  		Simplef: testSimpleFields{
   336  			S: strRpt(n, `some really really cool names that are nigerian and american like "ugorji melody nwoke" - get it? `),
   337  
   338  			// set the numbers close to the limits
   339  			I8:  math.MaxInt8 * 2 / 3,  // 8,
   340  			I64: math.MaxInt64 * 2 / 3, // 64,
   341  
   342  			Ui64: math.MaxUint64 * 2 / 3, // 64
   343  			Ui8:  math.MaxUint8 * 2 / 3,  // 8
   344  
   345  			F32: 3.402823e+38, // max representable float32 without losing precision
   346  			F64: 3.40281991833838838338e+53,
   347  
   348  			B: true,
   349  
   350  			Sslice:    []string{strRpt(n, "one"), strRpt(n, "two"), strRpt(n, "three")},
   351  			I32slice:  []int32{44, 55, 66},
   352  			Ui64slice: []uint64{12121212, 34343434, 56565656},
   353  			Ui8slice:  []uint8{210, 211, 212},
   354  			Bslice:    []bool{true, false, true, false},
   355  
   356  			Msint: map[string]int{
   357  				strRpt(n, "one"):       1,
   358  				strRpt(n, "two"):       2,
   359  				strRpt(n, "\"three\""): 3,
   360  			},
   361  
   362  			WrapSliceInt64:  []uint64{4, 16, 64, 256},
   363  			WrapSliceString: []string{strRpt(n, "4"), strRpt(n, "16"), strRpt(n, "64"), strRpt(n, "256")},
   364  		},
   365  
   366  		SstrUi64T:       make([]stringUint64T, numStrUi64T), // {{"1", 1}, {"2", 2}, {"3", 3}, {"4", 4}},
   367  		MstrUi64T:       make(map[string]*stringUint64T, numStrUi64T),
   368  		AnonInTestStruc: a,
   369  		NotAnon:         a,
   370  	}
   371  
   372  	for i := uint64(0); i < numStrUi64T; i++ {
   373  		ss := strings.Repeat(strconv.FormatUint(i, 10), int(i)) // 4)
   374  		ts.SstrUi64T[i] = stringUint64T{S: ss, U: i}
   375  		ts.MstrUi64T[ss] = &ts.SstrUi64T[i]
   376  	}
   377  
   378  	if bench {
   379  		ts.Ui64 = math.MaxInt64 * 2 / 3
   380  		ts.Simplef.Ui64 = ts.Ui64
   381  	}
   382  
   383  	//For benchmarks, some things will not work.
   384  	if !bench {
   385  		//json and bson require string keys in maps
   386  		//ts.M = map[interface{}]interface{}{
   387  		//	true: "true",
   388  		//	int8(9): false,
   389  		//}
   390  		//gob cannot encode nil in element in array (encodeArray: nil element)
   391  		ts.Iptrslice = []*int64{nil, &i64a, nil, &i64b, nil, &i64c, nil, &i64d, nil}
   392  		// ts.Iptrslice = nil
   393  	}
   394  	if !useStringKeyOnly {
   395  		var _ byte = 0 // so this empty branch doesn't flag a warning
   396  		// ts.AnonInTestStruc.AMU32F64 = map[uint32]float64{1: 1, 2: 2, 3: 3} // Json/Bson barf
   397  	}
   398  }
   399  
   400  func newTestStruc(depth, n int, bench, useInterface, useStringKeyOnly bool) (ts *TestStruc) {
   401  	ts = &TestStruc{}
   402  	populateTestStrucCommon(&ts.TestStrucCommon, n, bench, useInterface, useStringKeyOnly)
   403  	if depth > 0 {
   404  		depth--
   405  		if ts.Mtsptr == nil {
   406  			ts.Mtsptr = make(map[string]*TestStruc)
   407  		}
   408  		if ts.Mts == nil {
   409  			ts.Mts = make(map[string]TestStruc)
   410  		}
   411  		ts.Mtsptr[strRpt(n, "0")] = newTestStruc(depth, n, bench, useInterface, useStringKeyOnly)
   412  		ts.Mts[strRpt(n, "0")] = *(ts.Mtsptr[strRpt(n, "0")])
   413  		ts.Its = append(ts.Its, ts.Mtsptr[strRpt(n, "0")])
   414  	}
   415  	return
   416  }
   417  
   418  var testStrRptMap = make(map[int]map[string]string)
   419  
   420  func strRpt(n int, s string) string {
   421  	if false {
   422  		// fmt.Printf(">>>> calling strings.Repeat on n: %d, key: %s\n", n, s)
   423  		return strings.Repeat(s, n)
   424  	}
   425  	m1, ok := testStrRptMap[n]
   426  	if !ok {
   427  		// fmt.Printf(">>>> making new map for n: %v\n", n)
   428  		m1 = make(map[string]string)
   429  		testStrRptMap[n] = m1
   430  	}
   431  	v1, ok := m1[s]
   432  	if !ok {
   433  		// fmt.Printf(">>>> creating new entry for key: %s\n", s)
   434  		v1 = strings.Repeat(s, n)
   435  		m1[s] = v1
   436  	}
   437  	return v1
   438  }
   439  
   440  // func wstrRpt(n int, s string) wrapBytes {
   441  // 	 return wrapBytes(bytes.Repeat([]byte(s), n))
   442  // }