1
2
3
4
5
6
7 package bson
8
9 import (
10 "bytes"
11 "compress/gzip"
12 "encoding/json"
13 "fmt"
14 "io"
15 "io/ioutil"
16 "os"
17 "path"
18 "sync"
19 "testing"
20 )
21
22 type encodetest struct {
23 Field1String string
24 Field1Int64 int64
25 Field1Float64 float64
26 Field2String string
27 Field2Int64 int64
28 Field2Float64 float64
29 Field3String string
30 Field3Int64 int64
31 Field3Float64 float64
32 Field4String string
33 Field4Int64 int64
34 Field4Float64 float64
35 }
36
37 type nestedtest1 struct {
38 Nested nestedtest2
39 }
40
41 type nestedtest2 struct {
42 Nested nestedtest3
43 }
44
45 type nestedtest3 struct {
46 Nested nestedtest4
47 }
48
49 type nestedtest4 struct {
50 Nested nestedtest5
51 }
52
53 type nestedtest5 struct {
54 Nested nestedtest6
55 }
56
57 type nestedtest6 struct {
58 Nested nestedtest7
59 }
60
61 type nestedtest7 struct {
62 Nested nestedtest8
63 }
64
65 type nestedtest8 struct {
66 Nested nestedtest9
67 }
68
69 type nestedtest9 struct {
70 Nested nestedtest10
71 }
72
73 type nestedtest10 struct {
74 Nested nestedtest11
75 }
76
77 type nestedtest11 struct {
78 Nested encodetest
79 }
80
81 var encodetestInstance = encodetest{
82 Field1String: "foo",
83 Field1Int64: 1,
84 Field1Float64: 3.0,
85 Field2String: "bar",
86 Field2Int64: 2,
87 Field2Float64: 3.1,
88 Field3String: "baz",
89 Field3Int64: 3,
90 Field3Float64: 3.14,
91 Field4String: "qux",
92 Field4Int64: 4,
93 Field4Float64: 3.141,
94 }
95
96 var nestedInstance = nestedtest1{
97 nestedtest2{
98 nestedtest3{
99 nestedtest4{
100 nestedtest5{
101 nestedtest6{
102 nestedtest7{
103 nestedtest8{
104 nestedtest9{
105 nestedtest10{
106 nestedtest11{
107 encodetest{
108 Field1String: "foo",
109 Field1Int64: 1,
110 Field1Float64: 3.0,
111 Field2String: "bar",
112 Field2Int64: 2,
113 Field2Float64: 3.1,
114 Field3String: "baz",
115 Field3Int64: 3,
116 Field3Float64: 3.14,
117 Field4String: "qux",
118 Field4Int64: 4,
119 Field4Float64: 3.141,
120 },
121 },
122 },
123 },
124 },
125 },
126 },
127 },
128 },
129 },
130 },
131 }
132
133 const extendedBSONDir = "../testdata/extended_bson"
134
135 var (
136 extJSONFiles map[string]map[string]interface{}
137 extJSONFilesMu sync.Mutex
138 )
139
140
141
142
143 func readExtJSONFile(filename string) map[string]interface{} {
144 extJSONFilesMu.Lock()
145 defer extJSONFilesMu.Unlock()
146 if v, ok := extJSONFiles[filename]; ok {
147 return v
148 }
149 filePath := path.Join(extendedBSONDir, filename)
150 file, err := os.Open(filePath)
151 if err != nil {
152 panic(fmt.Sprintf("error opening file %q: %s", filePath, err))
153 }
154 defer func() {
155 _ = file.Close()
156 }()
157
158 gz, err := gzip.NewReader(file)
159 if err != nil {
160 panic(fmt.Sprintf("error creating GZIP reader: %s", err))
161 }
162 defer func() {
163 _ = gz.Close()
164 }()
165
166 data, err := ioutil.ReadAll(gz)
167 if err != nil {
168 panic(fmt.Sprintf("error reading GZIP contents of file: %s", err))
169 }
170
171 var v map[string]interface{}
172 err = UnmarshalExtJSON(data, false, &v)
173 if err != nil {
174 panic(fmt.Sprintf("error unmarshalling extended JSON: %s", err))
175 }
176
177 if extJSONFiles == nil {
178 extJSONFiles = make(map[string]map[string]interface{})
179 }
180 extJSONFiles[filename] = v
181 return v
182 }
183
184 func BenchmarkMarshal(b *testing.B) {
185 cases := []struct {
186 desc string
187 value interface{}
188 }{
189 {
190 desc: "simple struct",
191 value: encodetestInstance,
192 },
193 {
194 desc: "nested struct",
195 value: nestedInstance,
196 },
197 {
198 desc: "deep_bson.json.gz",
199 value: readExtJSONFile("deep_bson.json.gz"),
200 },
201 {
202 desc: "flat_bson.json.gz",
203 value: readExtJSONFile("flat_bson.json.gz"),
204 },
205 {
206 desc: "full_bson.json.gz",
207 value: readExtJSONFile("full_bson.json.gz"),
208 },
209 }
210
211 for _, tc := range cases {
212 b.Run(tc.desc, func(b *testing.B) {
213 b.Run("BSON", func(b *testing.B) {
214 for i := 0; i < b.N; i++ {
215 _, err := Marshal(tc.value)
216 if err != nil {
217 b.Errorf("error marshalling BSON: %s", err)
218 }
219 }
220 })
221
222 b.Run("extJSON", func(b *testing.B) {
223 for i := 0; i < b.N; i++ {
224 _, err := MarshalExtJSON(tc.value, true, false)
225 if err != nil {
226 b.Errorf("error marshalling extended JSON: %s", err)
227 }
228 }
229 })
230
231 b.Run("JSON", func(b *testing.B) {
232 for i := 0; i < b.N; i++ {
233 _, err := json.Marshal(tc.value)
234 if err != nil {
235 b.Errorf("error marshalling JSON: %s", err)
236 }
237 }
238 })
239 })
240 }
241 }
242
243 func BenchmarkUnmarshal(b *testing.B) {
244 cases := []struct {
245 desc string
246 value interface{}
247 }{
248 {
249 desc: "simple struct",
250 value: encodetestInstance,
251 },
252 {
253 desc: "nested struct",
254 value: nestedInstance,
255 },
256 {
257 desc: "deep_bson.json.gz",
258 value: readExtJSONFile("deep_bson.json.gz"),
259 },
260 {
261 desc: "flat_bson.json.gz",
262 value: readExtJSONFile("flat_bson.json.gz"),
263 },
264 {
265 desc: "full_bson.json.gz",
266 value: readExtJSONFile("full_bson.json.gz"),
267 },
268 }
269
270 for _, tc := range cases {
271 b.Run(tc.desc, func(b *testing.B) {
272 b.Run("BSON", func(b *testing.B) {
273 data, err := Marshal(tc.value)
274 if err != nil {
275 b.Errorf("error marshalling BSON: %s", err)
276 return
277 }
278
279 b.ResetTimer()
280 var v2 map[string]interface{}
281 for i := 0; i < b.N; i++ {
282 err := Unmarshal(data, &v2)
283 if err != nil {
284 b.Errorf("error unmarshalling BSON: %s", err)
285 }
286 }
287 })
288
289 b.Run("extJSON", func(b *testing.B) {
290 data, err := MarshalExtJSON(tc.value, true, false)
291 if err != nil {
292 b.Errorf("error marshalling extended JSON: %s", err)
293 return
294 }
295
296 b.ResetTimer()
297 var v2 map[string]interface{}
298 for i := 0; i < b.N; i++ {
299 err := UnmarshalExtJSON(data, true, &v2)
300 if err != nil {
301 b.Errorf("error unmarshalling extended JSON: %s", err)
302 }
303 }
304 })
305
306 b.Run("JSON", func(b *testing.B) {
307 data, err := json.Marshal(tc.value)
308 if err != nil {
309 b.Errorf("error marshalling JSON: %s", err)
310 return
311 }
312
313 b.ResetTimer()
314 var v2 map[string]interface{}
315 for i := 0; i < b.N; i++ {
316 err := json.Unmarshal(data, &v2)
317 if err != nil {
318 b.Errorf("error unmarshalling JSON: %s", err)
319 }
320 }
321 })
322 })
323 }
324 }
325
326
327
328
329 type codeResponse struct {
330 Tree *codeNode `json:"tree"`
331 Username string `json:"username"`
332 }
333
334 type codeNode struct {
335 Name string `json:"name"`
336 Kids []*codeNode `json:"kids"`
337 CLWeight float64 `json:"cl_weight"`
338 Touches int `json:"touches"`
339 MinT int64 `json:"min_t"`
340 MaxT int64 `json:"max_t"`
341 MeanT int64 `json:"mean_t"`
342 }
343
344 var codeJSON []byte
345 var codeBSON []byte
346 var codeStruct codeResponse
347
348 func codeInit() {
349 f, err := os.Open("testdata/code.json.gz")
350 if err != nil {
351 panic(err)
352 }
353 defer f.Close()
354 gz, err := gzip.NewReader(f)
355 if err != nil {
356 panic(err)
357 }
358 data, err := io.ReadAll(gz)
359 if err != nil {
360 panic(err)
361 }
362
363 codeJSON = data
364
365 if err := json.Unmarshal(codeJSON, &codeStruct); err != nil {
366 panic("json.Unmarshal code.json: " + err.Error())
367 }
368
369 if data, err = json.Marshal(&codeStruct); err != nil {
370 panic("json.Marshal code.json: " + err.Error())
371 }
372
373 if codeBSON, err = Marshal(&codeStruct); err != nil {
374 panic("Marshal code.json: " + err.Error())
375 }
376
377 if !bytes.Equal(data, codeJSON) {
378 println("different lengths", len(data), len(codeJSON))
379 for i := 0; i < len(data) && i < len(codeJSON); i++ {
380 if data[i] != codeJSON[i] {
381 println("re-marshal: changed at byte", i)
382 println("orig: ", string(codeJSON[i-10:i+10]))
383 println("new: ", string(data[i-10:i+10]))
384 break
385 }
386 }
387 panic("re-marshal code.json: different result")
388 }
389 }
390
391 func BenchmarkCodeUnmarshal(b *testing.B) {
392 b.ReportAllocs()
393 if codeJSON == nil {
394 b.StopTimer()
395 codeInit()
396 b.StartTimer()
397 }
398 b.Run("BSON", func(b *testing.B) {
399 b.RunParallel(func(pb *testing.PB) {
400 for pb.Next() {
401 var r codeResponse
402 if err := Unmarshal(codeBSON, &r); err != nil {
403 b.Fatal("Unmarshal:", err)
404 }
405 }
406 })
407 b.SetBytes(int64(len(codeBSON)))
408 })
409 b.Run("JSON", func(b *testing.B) {
410 b.RunParallel(func(pb *testing.PB) {
411 for pb.Next() {
412 var r codeResponse
413 if err := json.Unmarshal(codeJSON, &r); err != nil {
414 b.Fatal("json.Unmarshal:", err)
415 }
416 }
417 })
418 b.SetBytes(int64(len(codeJSON)))
419 })
420 }
421
422 func BenchmarkCodeMarshal(b *testing.B) {
423 b.ReportAllocs()
424 if codeJSON == nil {
425 b.StopTimer()
426 codeInit()
427 b.StartTimer()
428 }
429 b.Run("BSON", func(b *testing.B) {
430 b.RunParallel(func(pb *testing.PB) {
431 for pb.Next() {
432 if _, err := Marshal(&codeStruct); err != nil {
433 b.Fatal("Marshal:", err)
434 }
435 }
436 })
437 b.SetBytes(int64(len(codeBSON)))
438 })
439 b.Run("JSON", func(b *testing.B) {
440 b.RunParallel(func(pb *testing.PB) {
441 for pb.Next() {
442 if _, err := json.Marshal(&codeStruct); err != nil {
443 b.Fatal("json.Marshal:", err)
444 }
445 }
446 })
447 b.SetBytes(int64(len(codeJSON)))
448 })
449 }
450
View as plain text