1
2
3
4
5
6
7 package bson
8
9 import (
10 "errors"
11 "math/rand"
12 "reflect"
13 "sync"
14 "testing"
15
16 "go.mongodb.org/mongo-driver/bson/bsoncodec"
17 "go.mongodb.org/mongo-driver/bson/bsonrw"
18 "go.mongodb.org/mongo-driver/bson/primitive"
19 "go.mongodb.org/mongo-driver/internal/assert"
20 "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
21 )
22
23 func TestUnmarshal(t *testing.T) {
24 for _, tc := range unmarshalingTestCases() {
25 t.Run(tc.name, func(t *testing.T) {
26
27 data := make([]byte, len(tc.data))
28 copy(data, tc.data)
29
30
31 got := reflect.New(tc.sType).Interface()
32 err := Unmarshal(data, got)
33 noerr(t, err)
34 assert.Equal(t, tc.want, got, "Did not unmarshal as expected.")
35
36
37
38 _, err = rand.Read(data)
39 noerr(t, err)
40 assert.Equal(t, tc.want, got, "unmarshaled value does not match expected after modifying the input bytes")
41 })
42 }
43 }
44
45 func TestUnmarshalWithRegistry(t *testing.T) {
46 for _, tc := range unmarshalingTestCases() {
47 t.Run(tc.name, func(t *testing.T) {
48
49 data := make([]byte, len(tc.data))
50 copy(data, tc.data)
51
52
53 got := reflect.New(tc.sType).Interface()
54 err := UnmarshalWithRegistry(DefaultRegistry, data, got)
55 noerr(t, err)
56 assert.Equal(t, tc.want, got, "Did not unmarshal as expected.")
57
58
59
60 _, err = rand.Read(data)
61 noerr(t, err)
62 assert.Equal(t, tc.want, got, "unmarshaled value does not match expected after modifying the input bytes")
63 })
64 }
65 }
66
67 func TestUnmarshalWithContext(t *testing.T) {
68 for _, tc := range unmarshalingTestCases() {
69 t.Run(tc.name, func(t *testing.T) {
70
71 data := make([]byte, len(tc.data))
72 copy(data, tc.data)
73
74
75 dc := bsoncodec.DecodeContext{Registry: DefaultRegistry}
76 got := reflect.New(tc.sType).Interface()
77 err := UnmarshalWithContext(dc, data, got)
78 noerr(t, err)
79 assert.Equal(t, tc.want, got, "Did not unmarshal as expected.")
80
81
82
83 _, err = rand.Read(data)
84 noerr(t, err)
85 assert.Equal(t, tc.want, got, "unmarshaled value does not match expected after modifying the input bytes")
86 })
87 }
88 }
89
90 func TestUnmarshalExtJSONWithRegistry(t *testing.T) {
91 t.Run("UnmarshalExtJSONWithContext", func(t *testing.T) {
92 type teststruct struct{ Foo int }
93 var got teststruct
94 data := []byte("{\"foo\":1}")
95 err := UnmarshalExtJSONWithRegistry(DefaultRegistry, data, true, &got)
96 noerr(t, err)
97 want := teststruct{1}
98 assert.Equal(t, want, got, "Did not unmarshal as expected.")
99 })
100
101 t.Run("UnmarshalExtJSONInvalidInput", func(t *testing.T) {
102 data := []byte("invalid")
103 err := UnmarshalExtJSONWithRegistry(DefaultRegistry, data, true, &M{})
104 if !errors.Is(err, bsonrw.ErrInvalidJSON) {
105 t.Fatalf("wanted ErrInvalidJSON, got %v", err)
106 }
107 })
108 }
109
110 func TestUnmarshalExtJSONWithContext(t *testing.T) {
111 type fooInt struct {
112 Foo int
113 }
114
115 type fooString struct {
116 Foo string
117 }
118
119 type fooBytes struct {
120 Foo []byte
121 }
122
123 var cases = []struct {
124 name string
125 sType reflect.Type
126 want interface{}
127 data []byte
128 }{
129 {
130 name: "Small struct",
131 sType: reflect.TypeOf(fooInt{}),
132 data: []byte(`{"foo":1}`),
133 want: &fooInt{Foo: 1},
134 },
135 {
136 name: "Valid surrogate pair",
137 sType: reflect.TypeOf(fooString{}),
138 data: []byte(`{"foo":"\uD834\uDd1e"}`),
139 want: &fooString{Foo: "𝄞"},
140 },
141 {
142 name: "Valid surrogate pair with other values",
143 sType: reflect.TypeOf(fooString{}),
144 data: []byte(`{"foo":"abc \uD834\uDd1e 123"}`),
145 want: &fooString{Foo: "abc 𝄞 123"},
146 },
147 {
148 name: "High surrogate value with no following low surrogate value",
149 sType: reflect.TypeOf(fooString{}),
150 data: []byte(`{"foo":"abc \uD834 123"}`),
151 want: &fooString{Foo: "abc � 123"},
152 },
153 {
154 name: "High surrogate value at end of string",
155 sType: reflect.TypeOf(fooString{}),
156 data: []byte(`{"foo":"\uD834"}`),
157 want: &fooString{Foo: "�"},
158 },
159 {
160 name: "Low surrogate value with no preceding high surrogate value",
161 sType: reflect.TypeOf(fooString{}),
162 data: []byte(`{"foo":"abc \uDd1e 123"}`),
163 want: &fooString{Foo: "abc � 123"},
164 },
165 {
166 name: "Low surrogate value at end of string",
167 sType: reflect.TypeOf(fooString{}),
168 data: []byte(`{"foo":"\uDd1e"}`),
169 want: &fooString{Foo: "�"},
170 },
171 {
172 name: "High surrogate value with non-surrogate unicode value",
173 sType: reflect.TypeOf(fooString{}),
174 data: []byte(`{"foo":"\uD834\u00BF"}`),
175 want: &fooString{Foo: "�¿"},
176 },
177
178
179
180 {
181 name: "bson.D with binary",
182 sType: reflect.TypeOf(D{}),
183 data: []byte(`{"foo": {"$binary": {"subType": "0", "base64": "AAECAwQF"}}}`),
184 want: &D{{"foo", primitive.Binary{Subtype: 0, Data: []byte{0, 1, 2, 3, 4, 5}}}},
185 },
186
187
188
189 {
190 name: "struct with binary",
191 sType: reflect.TypeOf(fooBytes{}),
192 data: []byte(`{"foo": {"$binary": {"subType": "0", "base64": "AAECAwQF"}}}`),
193 want: &fooBytes{Foo: []byte{0, 1, 2, 3, 4, 5}},
194 },
195 }
196
197 for _, tc := range cases {
198 t.Run(tc.name, func(t *testing.T) {
199
200 data := make([]byte, len(tc.data))
201 copy(data, tc.data)
202
203
204 got := reflect.New(tc.sType).Interface()
205 dc := bsoncodec.DecodeContext{Registry: DefaultRegistry}
206 err := UnmarshalExtJSONWithContext(dc, data, true, got)
207 noerr(t, err)
208 assert.Equal(t, tc.want, got, "Did not unmarshal as expected.")
209
210
211
212 _, err = rand.Read(data)
213 noerr(t, err)
214 assert.Equal(t, tc.want, got, "unmarshaled value does not match expected after modifying the input bytes")
215 })
216 }
217 }
218
219 func TestCachingDecodersNotSharedAcrossRegistries(t *testing.T) {
220
221
222
223
224
225 var decodeInt32 bsoncodec.ValueDecoderFunc = func(_ bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
226 i32, err := vr.ReadInt32()
227 if err != nil {
228 return err
229 }
230
231 val.SetInt(int64(-1 * i32))
232 return nil
233 }
234 customReg := NewRegistryBuilder().
235 RegisterTypeDecoder(tInt32, decodeInt32).
236 Build()
237
238 docBytes := bsoncore.BuildDocumentFromElements(
239 nil,
240 bsoncore.AppendInt32Element(nil, "x", 1),
241 )
242
243
244
245 t.Run("struct", func(t *testing.T) {
246 type Struct struct {
247 X int32
248 }
249
250 var first Struct
251 err := Unmarshal(docBytes, &first)
252 assert.Nil(t, err, "Unmarshal error: %v", err)
253 assert.Equal(t, int32(1), first.X, "expected X value to be 1, got %v", first.X)
254
255 var second Struct
256 err = UnmarshalWithRegistry(customReg, docBytes, &second)
257 assert.Nil(t, err, "Unmarshal error: %v", err)
258 assert.Equal(t, int32(-1), second.X, "expected X value to be -1, got %v", second.X)
259 })
260 t.Run("pointer", func(t *testing.T) {
261 type Struct struct {
262 X *int32
263 }
264
265 var first Struct
266 err := Unmarshal(docBytes, &first)
267 assert.Nil(t, err, "Unmarshal error: %v", err)
268 assert.Equal(t, int32(1), *first.X, "expected X value to be 1, got %v", *first.X)
269
270 var second Struct
271 err = UnmarshalWithRegistry(customReg, docBytes, &second)
272 assert.Nil(t, err, "Unmarshal error: %v", err)
273 assert.Equal(t, int32(-1), *second.X, "expected X value to be -1, got %v", *second.X)
274 })
275 }
276
277 func TestUnmarshalExtJSONWithUndefinedField(t *testing.T) {
278
279
280 type expectedResponse struct {
281 DefinedField interface{}
282 }
283
284 unmarshalExpectedResponse := func(t *testing.T, extJSON string) *expectedResponse {
285 t.Helper()
286 responseDoc := expectedResponse{}
287 err := UnmarshalExtJSON([]byte(extJSON), false, &responseDoc)
288 assert.Nil(t, err, "UnmarshalExtJSON error: %v", err)
289 return &responseDoc
290 }
291
292 testCases := []struct {
293 name string
294 testJSON string
295 expectedValue interface{}
296 }{
297 {
298 "no array",
299 `{
300 "UndefinedField": {"key": 1},
301 "DefinedField": "value"
302 }`,
303 "value",
304 },
305 {
306 "outer array",
307 `{
308 "UndefinedField": [{"key": 1}],
309 "DefinedField": "value"
310 }`,
311 "value",
312 },
313 {
314 "embedded array",
315 `{
316 "UndefinedField": {"keys": [2]},
317 "DefinedField": "value"
318 }`,
319 "value",
320 },
321 {
322 "outer array and embedded array",
323 `{
324 "UndefinedField": [{"keys": [2]}],
325 "DefinedField": "value"
326 }`,
327 "value",
328 },
329 {
330 "embedded document",
331 `{
332 "UndefinedField": {"key": {"one": "two"}},
333 "DefinedField": "value"
334 }`,
335 "value",
336 },
337 {
338 "doubly embedded document",
339 `{
340 "UndefinedField": {"key": {"one": {"two": "three"}}},
341 "DefinedField": "value"
342 }`,
343 "value",
344 },
345 {
346 "embedded document and embedded array",
347 `{
348 "UndefinedField": {"key": {"one": {"two": [3]}}},
349 "DefinedField": "value"
350 }`,
351 "value",
352 },
353 {
354 "embedded document and embedded array in outer array",
355 `{
356 "UndefinedField": [{"key": {"one": [3]}}],
357 "DefinedField": "value"
358 }`,
359 "value",
360 },
361 {
362 "code with scope",
363 `{
364 "UndefinedField": {"logic": {"$code": "foo", "$scope": {"bar": 1}}},
365 "DefinedField": "value"
366 }`,
367 "value",
368 },
369 {
370 "embedded array of code with scope",
371 `{
372 "UndefinedField": {"logic": [{"$code": "foo", "$scope": {"bar": 1}}]},
373 "DefinedField": "value"
374 }`,
375 "value",
376 },
377 {
378 "type definition embedded document",
379 `{
380 "UndefinedField": {"myDouble": {"$numberDouble": "1.24"}},
381 "DefinedField": "value"
382 }`,
383 "value",
384 },
385 {
386 "empty embedded document",
387 `{
388 "UndefinedField": {"empty": {}, "key": 1},
389 "DefinedField": "value"
390 }`,
391 "value",
392 },
393 {
394 "empty object before",
395 `{
396 "UndefinedField": {},
397 "DefinedField": {"value": "a"}
398 }`,
399 D{{"value", "a"}},
400 },
401 {
402 "empty object after",
403 `{
404 "DefinedField": {"value": "a"},
405 "UndefinedField": {}
406 }`,
407 D{{"value", "a"}},
408 },
409 }
410 for _, tc := range testCases {
411 t.Run(tc.name, func(t *testing.T) {
412 responseDoc := unmarshalExpectedResponse(t, tc.testJSON)
413 assert.Equal(t, tc.expectedValue, responseDoc.DefinedField, "expected DefinedField to be %v, got %q",
414 tc.expectedValue, responseDoc.DefinedField)
415 })
416 }
417 }
418
419 func TestUnmarshalBSONWithUndefinedField(t *testing.T) {
420
421
422 type expectedResponse struct {
423 DefinedField string `bson:"DefinedField"`
424 }
425
426 createExpectedResponse := func(t *testing.T, doc D) *expectedResponse {
427 t.Helper()
428
429 marshalledBSON, err := Marshal(doc)
430 assert.Nil(t, err, "error marshalling BSON: %v", err)
431
432 responseDoc := expectedResponse{}
433 err = Unmarshal(marshalledBSON, &responseDoc)
434 assert.Nil(t, err, "error unmarshalling BSON: %v", err)
435 return &responseDoc
436 }
437
438 testCases := []struct {
439 name string
440 testBSON D
441 }{
442 {
443 "no array",
444 D{
445 {"UndefinedField", D{
446 {"key", 1},
447 }},
448 {"DefinedField", "value"},
449 },
450 },
451 {
452 "outer array",
453 D{
454 {"UndefinedField", A{D{
455 {"key", 1},
456 }}},
457 {"DefinedField", "value"},
458 },
459 },
460 {
461 "embedded array",
462 D{
463 {"UndefinedField", D{
464 {"key", A{1}},
465 }},
466 {"DefinedField", "value"},
467 },
468 },
469 {
470 "outer array and embedded array",
471 D{
472 {"UndefinedField", A{D{
473 {"key", A{1}},
474 }}},
475 {"DefinedField", "value"},
476 },
477 },
478 {
479 "embedded document",
480 D{
481 {"UndefinedField", D{
482 {"key", D{
483 {"one", "two"},
484 }},
485 }},
486 {"DefinedField", "value"},
487 },
488 },
489 {
490 "doubly embedded document",
491 D{
492 {"UndefinedField", D{
493 {"key", D{
494 {"one", D{
495 {"two", "three"},
496 }},
497 }},
498 }},
499 {"DefinedField", "value"},
500 },
501 },
502 {
503 "embedded document and embedded array",
504 D{
505 {"UndefinedField", D{
506 {"key", D{
507 {"one", D{
508 {"two", A{3}},
509 }},
510 }},
511 }},
512 {"DefinedField", "value"},
513 },
514 },
515 {
516 "embedded document and embedded array in outer array",
517 D{
518 {"UndefinedField", A{D{
519 {"key", D{
520 {"one", A{3}},
521 }},
522 }}},
523 {"DefinedField", "value"},
524 },
525 },
526 {
527 "code with scope",
528 D{
529 {"UndefinedField", D{
530 {"logic", D{
531 {"$code", "foo"},
532 {"$scope", D{
533 {"bar", 1},
534 }},
535 }},
536 }},
537 {"DefinedField", "value"},
538 },
539 },
540 {
541 "embedded array of code with scope",
542 D{
543 {"UndefinedField", D{
544 {"logic", A{D{
545 {"$code", "foo"},
546 {"$scope", D{
547 {"bar", 1},
548 }},
549 }}},
550 }},
551 {"DefinedField", "value"},
552 },
553 },
554 {
555 "empty embedded document",
556 D{
557 {"UndefinedField", D{}},
558 {"DefinedField", "value"},
559 },
560 },
561 }
562 for _, tc := range testCases {
563 t.Run(tc.name, func(t *testing.T) {
564 responseDoc := createExpectedResponse(t, tc.testBSON)
565 assert.Equal(t, "value", responseDoc.DefinedField, "expected DefinedField to be 'value', got %q", responseDoc.DefinedField)
566 })
567 }
568 }
569
570
571
572
573 func TestUnmarshalByteSlicesUseDistinctArrays(t *testing.T) {
574 type fooBytes struct {
575 Foo []byte
576 }
577
578 type myBytes []byte
579 type fooMyBytes struct {
580 Foo myBytes
581 }
582
583 type fooBinary struct {
584 Foo primitive.Binary
585 }
586
587 type fooObjectID struct {
588 Foo primitive.ObjectID
589 }
590
591 type fooDBPointer struct {
592 Foo primitive.DBPointer
593 }
594
595 testCases := []struct {
596 description string
597 data []byte
598 sType reflect.Type
599 want interface{}
600
601
602
603 getByteSlice func(interface{}) []byte
604 }{
605 {
606 description: "struct with byte slice",
607 data: docToBytes(fooBytes{
608 Foo: []byte{0, 1, 2, 3, 4, 5},
609 }),
610 sType: reflect.TypeOf(fooBytes{}),
611 want: &fooBytes{
612 Foo: []byte{0, 1, 2, 3, 4, 5},
613 },
614 getByteSlice: func(val interface{}) []byte {
615 return (*(val.(*fooBytes))).Foo
616 },
617 },
618 {
619 description: "bson.D with byte slice",
620 data: docToBytes(D{
621 {"foo", []byte{0, 1, 2, 3, 4, 5}},
622 }),
623 sType: reflect.TypeOf(D{}),
624 want: &D{
625 {"foo", primitive.Binary{Subtype: 0, Data: []byte{0, 1, 2, 3, 4, 5}}},
626 },
627 getByteSlice: func(val interface{}) []byte {
628 return (*(val.(*D)))[0].Value.(primitive.Binary).Data
629 },
630 },
631 {
632 description: "struct with custom byte slice type",
633 data: docToBytes(fooMyBytes{
634 Foo: myBytes{0, 1, 2, 3, 4, 5},
635 }),
636 sType: reflect.TypeOf(fooMyBytes{}),
637 want: &fooMyBytes{
638 Foo: myBytes{0, 1, 2, 3, 4, 5},
639 },
640 getByteSlice: func(val interface{}) []byte {
641 return (*(val.(*fooMyBytes))).Foo
642 },
643 },
644 {
645 description: "bson.D with custom byte slice type",
646 data: docToBytes(D{
647 {"foo", myBytes{0, 1, 2, 3, 4, 5}},
648 }),
649 sType: reflect.TypeOf(D{}),
650 want: &D{
651 {"foo", primitive.Binary{Subtype: 0, Data: myBytes{0, 1, 2, 3, 4, 5}}},
652 },
653 getByteSlice: func(val interface{}) []byte {
654 return (*(val.(*D)))[0].Value.(primitive.Binary).Data
655 },
656 },
657 {
658 description: "struct with primitive.Binary",
659 data: docToBytes(fooBinary{
660 Foo: primitive.Binary{Subtype: 0, Data: []byte{0, 1, 2, 3, 4, 5}},
661 }),
662 sType: reflect.TypeOf(fooBinary{}),
663 want: &fooBinary{
664 Foo: primitive.Binary{Subtype: 0, Data: []byte{0, 1, 2, 3, 4, 5}},
665 },
666 getByteSlice: func(val interface{}) []byte {
667 return (*(val.(*fooBinary))).Foo.Data
668 },
669 },
670 {
671 description: "bson.D with primitive.Binary",
672 data: docToBytes(D{
673 {"foo", primitive.Binary{Subtype: 0, Data: []byte{0, 1, 2, 3, 4, 5}}},
674 }),
675 sType: reflect.TypeOf(D{}),
676 want: &D{
677 {"foo", primitive.Binary{Subtype: 0, Data: []byte{0, 1, 2, 3, 4, 5}}},
678 },
679 getByteSlice: func(val interface{}) []byte {
680 return (*(val.(*D)))[0].Value.(primitive.Binary).Data
681 },
682 },
683 {
684 description: "struct with primitive.ObjectID",
685 data: docToBytes(fooObjectID{
686 Foo: primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
687 }),
688 sType: reflect.TypeOf(fooObjectID{}),
689 want: &fooObjectID{
690 Foo: primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
691 },
692 getByteSlice: func(val interface{}) []byte {
693 return (*(val.(*fooObjectID))).Foo[:]
694 },
695 },
696 {
697 description: "bson.D with primitive.ObjectID",
698 data: docToBytes(D{
699 {"foo", primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}},
700 }),
701 sType: reflect.TypeOf(D{}),
702 want: &D{
703 {"foo", primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}},
704 },
705 getByteSlice: func(val interface{}) []byte {
706 oid := (*(val.(*D)))[0].Value.(primitive.ObjectID)
707 return oid[:]
708 },
709 },
710 {
711 description: "struct with primitive.DBPointer",
712 data: docToBytes(fooDBPointer{
713 Foo: primitive.DBPointer{
714 DB: "test",
715 Pointer: primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
716 },
717 }),
718 sType: reflect.TypeOf(fooDBPointer{}),
719 want: &fooDBPointer{
720 Foo: primitive.DBPointer{
721 DB: "test",
722 Pointer: primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
723 },
724 },
725 getByteSlice: func(val interface{}) []byte {
726 return (*(val.(*fooDBPointer))).Foo.Pointer[:]
727 },
728 },
729 {
730 description: "bson.D with primitive.DBPointer",
731 data: docToBytes(D{
732 {"foo", primitive.DBPointer{
733 DB: "test",
734 Pointer: primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
735 }},
736 }),
737 sType: reflect.TypeOf(D{}),
738 want: &D{
739 {"foo", primitive.DBPointer{
740 DB: "test",
741 Pointer: primitive.ObjectID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11},
742 }},
743 },
744 getByteSlice: func(val interface{}) []byte {
745 oid := (*(val.(*D)))[0].Value.(primitive.DBPointer).Pointer
746 return oid[:]
747 },
748 },
749 }
750
751 for _, tc := range testCases {
752 tc := tc
753 t.Run(tc.description, func(t *testing.T) {
754 t.Parallel()
755
756
757 data := make([]byte, len(tc.data))
758 copy(data, tc.data)
759
760
761 got := reflect.New(tc.sType).Interface()
762 err := Unmarshal(data, got)
763 noerr(t, err)
764 assert.Equal(t, tc.want, got, "unmarshaled value does not match the expected value")
765
766
767
768 _, err = rand.Read(data)
769 noerr(t, err)
770 assert.Equal(t, tc.want, got, "unmarshaled value does not match expected after modifying the input bytes")
771
772
773
774 assert.DifferentAddressRanges(t, data, tc.getByteSlice(got))
775 })
776 }
777 }
778
779 func TestUnmarshalConcurrently(t *testing.T) {
780 t.Parallel()
781
782 const size = 10_000
783
784 data := []byte{16, 0, 0, 0, 10, 108, 97, 115, 116, 101, 114, 114, 111, 114, 0, 0}
785 wg := sync.WaitGroup{}
786 wg.Add(size)
787 for i := 0; i < size; i++ {
788 go func() {
789 defer wg.Done()
790 var res struct{ LastError error }
791 _ = Unmarshal(data, &res)
792 }()
793 }
794 wg.Wait()
795 }
796
View as plain text