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