1
2
3
4
5
6
7 package bson
8
9 import (
10 "bytes"
11 "encoding/json"
12 "errors"
13 "fmt"
14 "net/url"
15 "reflect"
16 "testing"
17 "time"
18
19 "github.com/google/go-cmp/cmp"
20 "go.mongodb.org/mongo-driver/bson/bsoncodec"
21 "go.mongodb.org/mongo-driver/bson/bsonrw"
22 "go.mongodb.org/mongo-driver/bson/bsonrw/bsonrwtest"
23 "go.mongodb.org/mongo-driver/bson/bsontype"
24 "go.mongodb.org/mongo-driver/bson/primitive"
25 "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
26 )
27
28 func bytesFromDoc(doc interface{}) []byte {
29 b, err := Marshal(doc)
30 if err != nil {
31 panic(fmt.Errorf("Couldn't marshal BSON document: %w", err))
32 }
33 return b
34 }
35
36 func compareDecimal128(d1, d2 primitive.Decimal128) bool {
37 d1H, d1L := d1.GetBytes()
38 d2H, d2L := d2.GetBytes()
39
40 if d1H != d2H {
41 return false
42 }
43
44 if d1L != d2L {
45 return false
46 }
47
48 return true
49 }
50
51 func compareErrors(err1, err2 error) bool {
52 if err1 == nil && err2 == nil {
53 return true
54 }
55
56 if err1 == nil || err2 == nil {
57 return false
58 }
59
60 if err1.Error() != err2.Error() {
61 return false
62 }
63
64 return true
65 }
66
67 func TestDefaultValueEncoders(t *testing.T) {
68 t.Parallel()
69
70 var pc PrimitiveCodecs
71
72 var wrong = func(string, string) string { return "wrong" }
73
74 type subtest struct {
75 name string
76 val interface{}
77 ectx *bsoncodec.EncodeContext
78 llvrw *bsonrwtest.ValueReaderWriter
79 invoke bsonrwtest.Invoked
80 err error
81 }
82
83 testCases := []struct {
84 name string
85 ve bsoncodec.ValueEncoder
86 subtests []subtest
87 }{
88 {
89 "RawValueEncodeValue",
90 bsoncodec.ValueEncoderFunc(pc.RawValueEncodeValue),
91 []subtest{
92 {
93 "wrong type",
94 wrong,
95 nil,
96 nil,
97 bsonrwtest.Nothing,
98 bsoncodec.ValueEncoderError{
99 Name: "RawValueEncodeValue",
100 Types: []reflect.Type{tRawValue},
101 Received: reflect.ValueOf(wrong),
102 },
103 },
104 {
105 "RawValue/success",
106 RawValue{Type: bsontype.Double, Value: bsoncore.AppendDouble(nil, 3.14159)},
107 nil,
108 nil,
109 bsonrwtest.WriteDouble,
110 nil,
111 },
112 {
113 "RawValue Type is zero with non-zero value",
114 RawValue{
115 Type: 0x00,
116 Value: bsoncore.AppendDouble(nil, 3.14159),
117 },
118 nil,
119 nil,
120 bsonrwtest.Nothing,
121 fmt.Errorf("the RawValue Type specifies an invalid BSON type: 0x0"),
122 },
123 {
124 "RawValue Type is invalid",
125 RawValue{
126 Type: 0x8F,
127 Value: bsoncore.AppendDouble(nil, 3.14159),
128 },
129 nil,
130 nil,
131 bsonrwtest.Nothing,
132 fmt.Errorf("the RawValue Type specifies an invalid BSON type: 0x8f"),
133 },
134 },
135 },
136 {
137 "RawEncodeValue",
138 bsoncodec.ValueEncoderFunc(pc.RawEncodeValue),
139 []subtest{
140 {
141 "wrong type",
142 wrong,
143 nil,
144 nil,
145 bsonrwtest.Nothing,
146 bsoncodec.ValueEncoderError{Name: "RawEncodeValue", Types: []reflect.Type{tRaw}, Received: reflect.ValueOf(wrong)},
147 },
148 {
149 "WriteDocument Error",
150 Raw{},
151 nil,
152 &bsonrwtest.ValueReaderWriter{Err: errors.New("wd error"), ErrAfter: bsonrwtest.WriteDocument},
153 bsonrwtest.WriteDocument,
154 errors.New("wd error"),
155 },
156 {
157 "Raw.Elements Error",
158 Raw{0xFF, 0x00, 0x00, 0x00, 0x00},
159 nil,
160 &bsonrwtest.ValueReaderWriter{},
161 bsonrwtest.WriteDocument,
162 errors.New("length read exceeds number of bytes available. length=5 bytes=255"),
163 },
164 {
165 "WriteDocumentElement Error",
166 Raw(bytesFromDoc(D{{"foo", nil}})),
167 nil,
168 &bsonrwtest.ValueReaderWriter{Err: errors.New("wde error"), ErrAfter: bsonrwtest.WriteDocumentElement},
169 bsonrwtest.WriteDocumentElement,
170 errors.New("wde error"),
171 },
172 {
173 "encodeValue error",
174 Raw(bytesFromDoc(D{{"foo", nil}})),
175 nil,
176 &bsonrwtest.ValueReaderWriter{Err: errors.New("ev error"), ErrAfter: bsonrwtest.WriteNull},
177 bsonrwtest.WriteNull,
178 errors.New("ev error"),
179 },
180 {
181 "iterator error",
182 Raw{0x0C, 0x00, 0x00, 0x00, 0x01, 'f', 'o', 'o', 0x00, 0x01, 0x02, 0x03},
183 nil,
184 &bsonrwtest.ValueReaderWriter{},
185 bsonrwtest.WriteDocumentElement,
186 errors.New("not enough bytes available to read type. bytes=3 type=double"),
187 },
188 },
189 },
190 }
191
192 for _, tc := range testCases {
193 tc := tc
194
195 t.Run(tc.name, func(t *testing.T) {
196 t.Parallel()
197
198 for _, subtest := range tc.subtests {
199 subtest := subtest
200
201 t.Run(subtest.name, func(t *testing.T) {
202 t.Parallel()
203
204 var ec bsoncodec.EncodeContext
205 if subtest.ectx != nil {
206 ec = *subtest.ectx
207 }
208 llvrw := new(bsonrwtest.ValueReaderWriter)
209 if subtest.llvrw != nil {
210 llvrw = subtest.llvrw
211 }
212 llvrw.T = t
213 err := tc.ve.EncodeValue(ec, llvrw, reflect.ValueOf(subtest.val))
214 if !compareErrors(err, subtest.err) {
215 t.Errorf("Errors do not match. got %v; want %v", err, subtest.err)
216 }
217 invoked := llvrw.Invoked
218 if !cmp.Equal(invoked, subtest.invoke) {
219 t.Errorf("Incorrect method invoked. got %v; want %v", invoked, subtest.invoke)
220 }
221 })
222 }
223 })
224 }
225
226 t.Run("success path", func(t *testing.T) {
227 t.Parallel()
228
229 oid := primitive.NewObjectID()
230 oids := []primitive.ObjectID{primitive.NewObjectID(), primitive.NewObjectID(), primitive.NewObjectID()}
231 var str = new(string)
232 *str = "bar"
233 now := time.Now().Truncate(time.Millisecond)
234 murl, err := url.Parse("https://mongodb.com/random-url?hello=world")
235 if err != nil {
236 t.Errorf("Error parsing URL: %v", err)
237 t.FailNow()
238 }
239 decimal128, err := primitive.ParseDecimal128("1.5e10")
240 if err != nil {
241 t.Errorf("Error parsing decimal128: %v", err)
242 t.FailNow()
243 }
244
245 testCases := []struct {
246 name string
247 value interface{}
248 b []byte
249 err error
250 }{
251 {
252 "D to JavaScript",
253 D{{"a", primitive.JavaScript(`function() { var hello = "world"; }`)}},
254 docToBytes(D{{"a", primitive.JavaScript(`function() { var hello = "world"; }`)}}),
255 nil,
256 },
257 {
258 "D to Symbol",
259 D{{"a", primitive.Symbol("foobarbaz")}},
260 docToBytes(D{{"a", primitive.Symbol("foobarbaz")}}),
261 nil,
262 },
263 {
264 "omitempty map",
265 struct {
266 T map[string]string `bson:",omitempty"`
267 }{
268 T: map[string]string{},
269 },
270 docToBytes(D{}),
271 nil,
272 },
273 {
274 "omitempty slice",
275 struct {
276 T []struct{} `bson:",omitempty"`
277 }{
278 T: []struct{}{},
279 },
280 docToBytes(D{}),
281 nil,
282 },
283 {
284 "omitempty string",
285 struct {
286 T string `bson:",omitempty"`
287 }{
288 T: "",
289 },
290 docToBytes(D{}),
291 nil,
292 },
293 {
294 "struct{}",
295 struct {
296 A bool
297 B int32
298 C int64
299 D uint16
300 E uint64
301 F float64
302 G string
303 H map[string]string
304 I []byte
305 K [2]string
306 L struct {
307 M string
308 }
309 P Raw
310 Q primitive.ObjectID
311 T []struct{}
312 Y json.Number
313 Z time.Time
314 AA json.Number
315 AB *url.URL
316 AC primitive.Decimal128
317 AD *time.Time
318 AE testValueMarshaler
319 AF RawValue
320 AG *RawValue
321 AH D
322 AI *D
323 AJ *D
324 }{
325 A: true,
326 B: 123,
327 C: 456,
328 D: 789,
329 E: 101112,
330 F: 3.14159,
331 G: "Hello, world",
332 H: map[string]string{"foo": "bar"},
333 I: []byte{0x01, 0x02, 0x03},
334 K: [2]string{"baz", "qux"},
335 L: struct {
336 M string
337 }{
338 M: "foobar",
339 },
340 P: Raw{0x05, 0x00, 0x00, 0x00, 0x00},
341 Q: oid,
342 T: nil,
343 Y: json.Number("5"),
344 Z: now,
345 AA: json.Number("10.1"),
346 AB: murl,
347 AC: decimal128,
348 AD: &now,
349 AE: testValueMarshaler{t: TypeString, buf: bsoncore.AppendString(nil, "hello, world")},
350 AF: RawValue{Type: bsontype.String, Value: bsoncore.AppendString(nil, "hello, raw value")},
351 AG: &RawValue{Type: bsontype.Double, Value: bsoncore.AppendDouble(nil, 3.14159)},
352 AH: D{{"foo", "bar"}},
353 AI: &D{{"pi", 3.14159}},
354 AJ: nil,
355 },
356 docToBytes(D{
357 {"a", true},
358 {"b", int32(123)},
359 {"c", int64(456)},
360 {"d", int32(789)},
361 {"e", int64(101112)},
362 {"f", float64(3.14159)},
363 {"g", "Hello, world"},
364 {"h", D{{"foo", "bar"}}},
365 {"i", primitive.Binary{Subtype: 0x00, Data: []byte{0x01, 0x02, 0x03}}},
366 {"k", A{"baz", "qux"}},
367 {"l", D{{"m", "foobar"}}},
368 {"p", D{}},
369 {"q", oid},
370 {"t", nil},
371 {"y", int64(5)},
372 {"z", primitive.DateTime(now.UnixNano() / int64(time.Millisecond))},
373 {"aa", float64(10.1)},
374 {"ab", murl.String()},
375 {"ac", decimal128},
376 {"ad", primitive.DateTime(now.UnixNano() / int64(time.Millisecond))},
377 {"ae", "hello, world"},
378 {"af", "hello, raw value"},
379 {"ag", 3.14159},
380 {"ah", D{{"foo", "bar"}}},
381 {"ai", D{{"pi", float64(3.14159)}}},
382 {"aj", nil},
383 }),
384 nil,
385 },
386 {
387 "struct{[]interface{}}",
388 struct {
389 A []bool
390 B []int32
391 C []int64
392 D []uint16
393 E []uint64
394 F []float64
395 G []string
396 H []map[string]string
397 I [][]byte
398 K [1][2]string
399 L []struct {
400 M string
401 }
402 N [][]string
403 Q []Raw
404 R []primitive.ObjectID
405 T []struct{}
406 W []map[string]struct{}
407 X []map[string]struct{}
408 Y []map[string]struct{}
409 Z []time.Time
410 AA []json.Number
411 AB []*url.URL
412 AC []primitive.Decimal128
413 AD []*time.Time
414 AE []testValueMarshaler
415 AF []D
416 AG []*D
417 }{
418 A: []bool{true},
419 B: []int32{123},
420 C: []int64{456},
421 D: []uint16{789},
422 E: []uint64{101112},
423 F: []float64{3.14159},
424 G: []string{"Hello, world"},
425 H: []map[string]string{{"foo": "bar"}},
426 I: [][]byte{{0x01, 0x02, 0x03}},
427 K: [1][2]string{{"baz", "qux"}},
428 L: []struct {
429 M string
430 }{
431 {
432 M: "foobar",
433 },
434 },
435 N: [][]string{{"foo", "bar"}},
436 Q: []Raw{{0x05, 0x00, 0x00, 0x00, 0x00}},
437 R: oids,
438 T: nil,
439 W: nil,
440 X: []map[string]struct{}{},
441 Y: []map[string]struct{}{{}},
442 Z: []time.Time{now, now},
443 AA: []json.Number{json.Number("5"), json.Number("10.1")},
444 AB: []*url.URL{murl},
445 AC: []primitive.Decimal128{decimal128},
446 AD: []*time.Time{&now, &now},
447 AE: []testValueMarshaler{
448 {t: TypeString, buf: bsoncore.AppendString(nil, "hello")},
449 {t: TypeString, buf: bsoncore.AppendString(nil, "world")},
450 },
451 AF: []D{{{"foo", "bar"}}, {{"hello", "world"}, {"number", 12345}}},
452 AG: []*D{{{"pi", 3.14159}}, nil},
453 },
454 docToBytes(D{
455 {"a", A{true}},
456 {"b", A{int32(123)}},
457 {"c", A{int64(456)}},
458 {"d", A{int32(789)}},
459 {"e", A{int64(101112)}},
460 {"f", A{float64(3.14159)}},
461 {"g", A{"Hello, world"}},
462 {"h", A{D{{"foo", "bar"}}}},
463 {"i", A{primitive.Binary{Subtype: 0x00, Data: []byte{0x01, 0x02, 0x03}}}},
464 {"k", A{A{"baz", "qux"}}},
465 {"l", A{D{{"m", "foobar"}}}},
466 {"n", A{A{"foo", "bar"}}},
467 {"q", A{D{}}},
468 {"r", A{oids[0], oids[1], oids[2]}},
469 {"t", nil},
470 {"w", nil},
471 {"x", A{}},
472 {"y", A{D{}}},
473 {"z", A{
474 primitive.DateTime(now.UnixNano() / int64(time.Millisecond)),
475 primitive.DateTime(now.UnixNano() / int64(time.Millisecond)),
476 }},
477 {"aa", A{int64(5), float64(10.10)}},
478 {"ab", A{murl.String()}},
479 {"ac", A{decimal128}},
480 {"ad", A{
481 primitive.DateTime(now.UnixNano() / int64(time.Millisecond)),
482 primitive.DateTime(now.UnixNano() / int64(time.Millisecond)),
483 }},
484 {"ae", A{"hello", "world"}},
485 {"af", A{D{{"foo", "bar"}}, D{{"hello", "world"}, {"number", int32(12345)}}}},
486 {"ag", A{D{{"pi", float64(3.14159)}}, nil}},
487 }),
488 nil,
489 },
490 }
491
492 for _, tc := range testCases {
493 tc := tc
494
495 t.Run(tc.name, func(t *testing.T) {
496 t.Parallel()
497
498 b := make(bsonrw.SliceWriter, 0, 512)
499 vw, err := bsonrw.NewBSONValueWriter(&b)
500 noerr(t, err)
501 enc, err := NewEncoder(vw)
502 noerr(t, err)
503 err = enc.Encode(tc.value)
504 if !errors.Is(err, tc.err) {
505 t.Errorf("Did not receive expected error. got %v; want %v", err, tc.err)
506 }
507 if diff := cmp.Diff([]byte(b), tc.b); diff != "" {
508 t.Errorf("Bytes written differ: (-got +want)\n%s", diff)
509 t.Errorf("Bytes\ngot: %v\nwant:%v\n", b, tc.b)
510 t.Errorf("Readers\ngot: %v\nwant:%v\n", Raw(b), Raw(tc.b))
511 }
512 })
513 }
514 })
515 }
516
517 func TestDefaultValueDecoders(t *testing.T) {
518 var pc PrimitiveCodecs
519
520 var wrong = func(string, string) string { return "wrong" }
521
522 const cansetreflectiontest = "cansetreflectiontest"
523
524 type subtest struct {
525 name string
526 val interface{}
527 dctx *bsoncodec.DecodeContext
528 llvrw *bsonrwtest.ValueReaderWriter
529 invoke bsonrwtest.Invoked
530 err error
531 }
532
533 testCases := []struct {
534 name string
535 vd bsoncodec.ValueDecoder
536 subtests []subtest
537 }{
538 {
539 "RawValueDecodeValue",
540 bsoncodec.ValueDecoderFunc(pc.RawValueDecodeValue),
541 []subtest{
542 {
543 "wrong type",
544 wrong,
545 nil,
546 &bsonrwtest.ValueReaderWriter{},
547 bsonrwtest.Nothing,
548 bsoncodec.ValueDecoderError{
549 Name: "RawValueDecodeValue",
550 Types: []reflect.Type{tRawValue},
551 Received: reflect.ValueOf(wrong),
552 },
553 },
554 {
555 "ReadValue Error",
556 RawValue{},
557 nil,
558 &bsonrwtest.ValueReaderWriter{
559 BSONType: bsontype.Binary,
560 Err: errors.New("rb error"),
561 ErrAfter: bsonrwtest.ReadBinary,
562 },
563 bsonrwtest.ReadBinary,
564 errors.New("rb error"),
565 },
566 {
567 "RawValue/success",
568 RawValue{Type: bsontype.Binary, Value: bsoncore.AppendBinary(nil, 0xFF, []byte{0x01, 0x02, 0x03})},
569 nil,
570 &bsonrwtest.ValueReaderWriter{
571 BSONType: bsontype.Binary,
572 Return: bsoncore.Value{
573 Type: bsontype.Binary,
574 Data: bsoncore.AppendBinary(nil, 0xFF, []byte{0x01, 0x02, 0x03}),
575 },
576 },
577 bsonrwtest.ReadBinary,
578 nil,
579 },
580 },
581 },
582 {
583 "RawDecodeValue",
584 bsoncodec.ValueDecoderFunc(pc.RawDecodeValue),
585 []subtest{
586 {
587 "wrong type",
588 wrong,
589 nil,
590 &bsonrwtest.ValueReaderWriter{},
591 bsonrwtest.Nothing,
592 bsoncodec.ValueDecoderError{Name: "RawDecodeValue", Types: []reflect.Type{tRaw}, Received: reflect.ValueOf(wrong)},
593 },
594 {
595 "*Raw is nil",
596 (*Raw)(nil),
597 nil,
598 nil,
599 bsonrwtest.Nothing,
600 bsoncodec.ValueDecoderError{
601 Name: "RawDecodeValue",
602 Types: []reflect.Type{tRaw},
603 Received: reflect.ValueOf((*Raw)(nil)),
604 },
605 },
606 {
607 "Copy error",
608 Raw{},
609 nil,
610 &bsonrwtest.ValueReaderWriter{Err: errors.New("copy error"), ErrAfter: bsonrwtest.ReadDocument},
611 bsonrwtest.ReadDocument,
612 errors.New("copy error"),
613 },
614 },
615 },
616 }
617
618 for _, tc := range testCases {
619 t.Run(tc.name, func(t *testing.T) {
620 for _, rc := range tc.subtests {
621 t.Run(rc.name, func(t *testing.T) {
622 var dc bsoncodec.DecodeContext
623 if rc.dctx != nil {
624 dc = *rc.dctx
625 }
626 llvrw := new(bsonrwtest.ValueReaderWriter)
627 if rc.llvrw != nil {
628 llvrw = rc.llvrw
629 }
630 llvrw.T = t
631 if rc.val == cansetreflectiontest {
632 err := tc.vd.DecodeValue(dc, llvrw, reflect.Value{})
633 if !compareErrors(err, rc.err) {
634 t.Errorf("Errors do not match. got %v; want %v", err, rc.err)
635 }
636
637 val := reflect.New(reflect.TypeOf(rc.val)).Elem()
638 err = tc.vd.DecodeValue(dc, llvrw, val)
639 if !compareErrors(err, rc.err) {
640 t.Errorf("Errors do not match. got %v; want %v", err, rc.err)
641 }
642 return
643 }
644 var val reflect.Value
645 if rtype := reflect.TypeOf(rc.val); rtype != nil {
646 val = reflect.New(rtype).Elem()
647 }
648 want := rc.val
649 defer func() {
650 if err := recover(); err != nil {
651 fmt.Println(t.Name())
652 panic(err)
653 }
654 }()
655 err := tc.vd.DecodeValue(dc, llvrw, val)
656 if !compareErrors(err, rc.err) {
657 t.Errorf("Errors do not match. got %v; want %v", err, rc.err)
658 }
659 invoked := llvrw.Invoked
660 if !cmp.Equal(invoked, rc.invoke) {
661 t.Errorf("Incorrect method invoked. got %v; want %v", invoked, rc.invoke)
662 }
663 var got interface{}
664 if val.IsValid() && val.CanInterface() {
665 got = val.Interface()
666 }
667 if rc.err == nil && !cmp.Equal(got, want) {
668 t.Errorf("Values do not match. got (%T)%v; want (%T)%v", got, got, want, want)
669 }
670 })
671 }
672 })
673 }
674
675 t.Run("success path", func(t *testing.T) {
676 oid := primitive.NewObjectID()
677 oids := []primitive.ObjectID{primitive.NewObjectID(), primitive.NewObjectID(), primitive.NewObjectID()}
678 var str = new(string)
679 *str = "bar"
680 now := time.Now().Truncate(time.Millisecond)
681 murl, err := url.Parse("https://mongodb.com/random-url?hello=world")
682 if err != nil {
683 t.Errorf("Error parsing URL: %v", err)
684 t.FailNow()
685 }
686 decimal128, err := primitive.ParseDecimal128("1.5e10")
687 if err != nil {
688 t.Errorf("Error parsing decimal128: %v", err)
689 t.FailNow()
690 }
691
692 testCases := []struct {
693 name string
694 value interface{}
695 b []byte
696 err error
697 }{
698 {
699 "map[string]int",
700 map[string]int32{"foo": 1},
701 []byte{
702 0x0E, 0x00, 0x00, 0x00,
703 0x10, 'f', 'o', 'o', 0x00,
704 0x01, 0x00, 0x00, 0x00,
705 0x00,
706 },
707 nil,
708 },
709 {
710 "map[string]primitive.ObjectID",
711 map[string]primitive.ObjectID{"foo": oid},
712 docToBytes(D{{"foo", oid}}),
713 nil,
714 },
715 {
716 "map[string]Reader",
717 map[string]Raw{"Z": {0x05, 0x00, 0x00, 0x00, 0x00}},
718 docToBytes(D{{"Z", Raw{0x05, 0x00, 0x00, 0x00, 0x00}}}),
719 nil,
720 },
721 {
722 "map[string][]int32",
723 map[string][]int32{"Z": {1, 2, 3}},
724 docToBytes(D{{"Z", A{int32(1), int32(2), int32(3)}}}),
725 nil,
726 },
727 {
728 "map[string][]primitive.ObjectID",
729 map[string][]primitive.ObjectID{"Z": oids},
730 docToBytes(D{{"Z", A{oids[0], oids[1], oids[2]}}}),
731 nil,
732 },
733 {
734 "map[string][]json.Number(int64)",
735 map[string][]json.Number{"Z": {json.Number("5"), json.Number("10")}},
736 docToBytes(D{{"Z", A{int64(5), int64(10)}}}),
737 nil,
738 },
739 {
740 "map[string][]json.Number(float64)",
741 map[string][]json.Number{"Z": {json.Number("5"), json.Number("10.1")}},
742 docToBytes(D{{"Z", A{int64(5), float64(10.1)}}}),
743 nil,
744 },
745 {
746 "map[string][]*url.URL",
747 map[string][]*url.URL{"Z": {murl}},
748 docToBytes(D{{"Z", A{murl.String()}}}),
749 nil,
750 },
751 {
752 "map[string][]primitive.Decimal128",
753 map[string][]primitive.Decimal128{"Z": {decimal128}},
754 docToBytes(D{{"Z", A{decimal128}}}),
755 nil,
756 },
757 {
758 "-",
759 struct {
760 A string `bson:"-"`
761 }{
762 A: "",
763 },
764 docToBytes(D{}),
765 nil,
766 },
767 {
768 "omitempty",
769 struct {
770 A string `bson:",omitempty"`
771 }{
772 A: "",
773 },
774 docToBytes(D{}),
775 nil,
776 },
777 {
778 "omitempty, empty time",
779 struct {
780 A time.Time `bson:",omitempty"`
781 }{
782 A: time.Time{},
783 },
784 docToBytes(D{}),
785 nil,
786 },
787 {
788 "no private fields",
789 noPrivateFields{a: "should be empty"},
790 docToBytes(D{}),
791 nil,
792 },
793 {
794 "minsize",
795 struct {
796 A int64 `bson:",minsize"`
797 }{
798 A: 12345,
799 },
800 docToBytes(D{{"a", int32(12345)}}),
801 nil,
802 },
803 {
804 "inline",
805 struct {
806 Foo struct {
807 A int64 `bson:",minsize"`
808 } `bson:",inline"`
809 }{
810 Foo: struct {
811 A int64 `bson:",minsize"`
812 }{
813 A: 12345,
814 },
815 },
816 docToBytes(D{{"a", int32(12345)}}),
817 nil,
818 },
819 {
820 "inline map",
821 struct {
822 Foo map[string]string `bson:",inline"`
823 }{
824 Foo: map[string]string{"foo": "bar"},
825 },
826 docToBytes(D{{"foo", "bar"}}),
827 nil,
828 },
829 {
830 "alternate name bson:name",
831 struct {
832 A string `bson:"foo"`
833 }{
834 A: "bar",
835 },
836 docToBytes(D{{"foo", "bar"}}),
837 nil,
838 },
839 {
840 "alternate name",
841 struct {
842 A string `bson:"foo"`
843 }{
844 A: "bar",
845 },
846 docToBytes(D{{"foo", "bar"}}),
847 nil,
848 },
849 {
850 "inline, omitempty",
851 struct {
852 A string
853 Foo zeroTest `bson:"omitempty,inline"`
854 }{
855 A: "bar",
856 Foo: zeroTest{true},
857 },
858 docToBytes(D{{"a", "bar"}}),
859 nil,
860 },
861 {
862 "JavaScript to D",
863 D{{"a", primitive.JavaScript(`function() { var hello = "world"; }`)}},
864 docToBytes(D{{"a", primitive.JavaScript(`function() { var hello = "world"; }`)}}),
865 nil,
866 },
867 {
868 "Symbol to D",
869 D{{"a", primitive.Symbol("foobarbaz")}},
870 docToBytes(D{{"a", primitive.Symbol("foobarbaz")}}),
871 nil,
872 },
873 {
874 "struct{}",
875 struct {
876 A bool
877 B int32
878 C int64
879 D uint16
880 E uint64
881 F float64
882 G string
883 H map[string]string
884 I []byte
885 K [2]string
886 L struct {
887 M string
888 }
889 P Raw
890 Q primitive.ObjectID
891 T []struct{}
892 Y json.Number
893 Z time.Time
894 AA json.Number
895 AB *url.URL
896 AC primitive.Decimal128
897 AD *time.Time
898 AE *testValueUnmarshaler
899 AF RawValue
900 AG *RawValue
901 AH D
902 AI *D
903 AJ *D
904 }{
905 A: true,
906 B: 123,
907 C: 456,
908 D: 789,
909 E: 101112,
910 F: 3.14159,
911 G: "Hello, world",
912 H: map[string]string{"foo": "bar"},
913 I: []byte{0x01, 0x02, 0x03},
914 K: [2]string{"baz", "qux"},
915 L: struct {
916 M string
917 }{
918 M: "foobar",
919 },
920 P: Raw{0x05, 0x00, 0x00, 0x00, 0x00},
921 Q: oid,
922 T: nil,
923 Y: json.Number("5"),
924 Z: now,
925 AA: json.Number("10.1"),
926 AB: murl,
927 AC: decimal128,
928 AD: &now,
929 AE: &testValueUnmarshaler{t: bsontype.String, val: bsoncore.AppendString(nil, "hello, world!")},
930 AF: RawValue{Type: bsontype.Double, Value: bsoncore.AppendDouble(nil, 3.14159)},
931 AG: &RawValue{Type: bsontype.Binary, Value: bsoncore.AppendBinary(nil, 0xFF, []byte{0x01, 0x02, 0x03})},
932 AH: D{{"foo", "bar"}},
933 AI: &D{{"pi", 3.14159}},
934 AJ: nil,
935 },
936 docToBytes(D{
937 {"a", true},
938 {"b", int32(123)},
939 {"c", int64(456)},
940 {"d", int32(789)},
941 {"e", int64(101112)},
942 {"f", float64(3.14159)},
943 {"g", "Hello, world"},
944 {"h", D{{"foo", "bar"}}},
945 {"i", primitive.Binary{Subtype: 0x00, Data: []byte{0x01, 0x02, 0x03}}},
946 {"k", A{"baz", "qux"}},
947 {"l", D{{"m", "foobar"}}},
948 {"p", D{}},
949 {"q", oid},
950 {"t", nil},
951 {"y", int64(5)},
952 {"z", primitive.DateTime(now.UnixNano() / int64(time.Millisecond))},
953 {"aa", float64(10.1)},
954 {"ab", murl.String()},
955 {"ac", decimal128},
956 {"ad", primitive.DateTime(now.UnixNano() / int64(time.Millisecond))},
957 {"ae", "hello, world!"},
958 {"af", float64(3.14159)},
959 {"ag", primitive.Binary{Subtype: 0xFF, Data: []byte{0x01, 0x02, 0x03}}},
960 {"ah", D{{"foo", "bar"}}},
961 {"ai", D{{"pi", float64(3.14159)}}},
962 {"aj", nil},
963 }),
964 nil,
965 },
966 {
967 "struct{[]interface{}}",
968 struct {
969 A []bool
970 B []int32
971 C []int64
972 D []uint16
973 E []uint64
974 F []float64
975 G []string
976 H []map[string]string
977 I [][]byte
978 K [1][2]string
979 L []struct {
980 M string
981 }
982 N [][]string
983 Q []Raw
984 R []primitive.ObjectID
985 T []struct{}
986 W []map[string]struct{}
987 X []map[string]struct{}
988 Y []map[string]struct{}
989 Z []time.Time
990 AA []json.Number
991 AB []*url.URL
992 AC []primitive.Decimal128
993 AD []*time.Time
994 AE []*testValueUnmarshaler
995 AF []D
996 AG []*D
997 }{
998 A: []bool{true},
999 B: []int32{123},
1000 C: []int64{456},
1001 D: []uint16{789},
1002 E: []uint64{101112},
1003 F: []float64{3.14159},
1004 G: []string{"Hello, world"},
1005 H: []map[string]string{{"foo": "bar"}},
1006 I: [][]byte{{0x01, 0x02, 0x03}},
1007 K: [1][2]string{{"baz", "qux"}},
1008 L: []struct {
1009 M string
1010 }{
1011 {
1012 M: "foobar",
1013 },
1014 },
1015 N: [][]string{{"foo", "bar"}},
1016 Q: []Raw{{0x05, 0x00, 0x00, 0x00, 0x00}},
1017 R: oids,
1018 T: nil,
1019 W: nil,
1020 X: []map[string]struct{}{},
1021 Y: []map[string]struct{}{{}},
1022 Z: []time.Time{now, now},
1023 AA: []json.Number{json.Number("5"), json.Number("10.1")},
1024 AB: []*url.URL{murl},
1025 AC: []primitive.Decimal128{decimal128},
1026 AD: []*time.Time{&now, &now},
1027 AE: []*testValueUnmarshaler{
1028 {t: bsontype.String, val: bsoncore.AppendString(nil, "hello")},
1029 {t: bsontype.String, val: bsoncore.AppendString(nil, "world")},
1030 },
1031 AF: []D{{{"foo", "bar"}}, {{"hello", "world"}, {"number", int64(12345)}}},
1032 AG: []*D{{{"pi", 3.14159}}, nil},
1033 },
1034 docToBytes(D{
1035 {"a", A{true}},
1036 {"b", A{int32(123)}},
1037 {"c", A{int64(456)}},
1038 {"d", A{int32(789)}},
1039 {"e", A{int64(101112)}},
1040 {"f", A{float64(3.14159)}},
1041 {"g", A{"Hello, world"}},
1042 {"h", A{D{{"foo", "bar"}}}},
1043 {"i", A{primitive.Binary{Subtype: 0x00, Data: []byte{0x01, 0x02, 0x03}}}},
1044 {"k", A{A{"baz", "qux"}}},
1045 {"l", A{D{{"m", "foobar"}}}},
1046 {"n", A{A{"foo", "bar"}}},
1047 {"q", A{D{}}},
1048 {"r", A{oids[0], oids[1], oids[2]}},
1049 {"t", nil},
1050 {"w", nil},
1051 {"x", A{}},
1052 {"y", A{D{}}},
1053 {"z", A{
1054 primitive.DateTime(now.UnixNano() / int64(time.Millisecond)),
1055 primitive.DateTime(now.UnixNano() / int64(time.Millisecond)),
1056 }},
1057 {"aa", A{int64(5), float64(10.10)}},
1058 {"ab", A{murl.String()}},
1059 {"ac", A{decimal128}},
1060 {"ad", A{
1061 primitive.DateTime(now.UnixNano() / int64(time.Millisecond)),
1062 primitive.DateTime(now.UnixNano() / int64(time.Millisecond)),
1063 }},
1064 {"ae", A{"hello", "world"}},
1065 {"af", A{
1066 D{{"foo", "bar"}},
1067 D{{"hello", "world"}, {"number", int64(12345)}},
1068 }},
1069 {"ag", A{D{{"pi", float64(3.14159)}}, nil}},
1070 }),
1071 nil,
1072 },
1073 }
1074
1075 t.Run("Decode", func(t *testing.T) {
1076 for _, tc := range testCases {
1077 t.Run(tc.name, func(t *testing.T) {
1078 vr := bsonrw.NewBSONDocumentReader(tc.b)
1079 dec, err := NewDecoder(vr)
1080 noerr(t, err)
1081 gotVal := reflect.New(reflect.TypeOf(tc.value))
1082 err = dec.Decode(gotVal.Interface())
1083 noerr(t, err)
1084 got := gotVal.Elem().Interface()
1085 want := tc.value
1086 if diff := cmp.Diff(
1087 got, want,
1088 cmp.Comparer(compareDecimal128),
1089 cmp.Comparer(compareNoPrivateFields),
1090 cmp.Comparer(compareZeroTest),
1091 ); diff != "" {
1092 t.Errorf("difference:\n%s", diff)
1093 t.Errorf("Values are not equal.\ngot: %#v\nwant:%#v", got, want)
1094 }
1095 })
1096 }
1097 })
1098 })
1099 }
1100
1101 type testValueMarshaler struct {
1102 t bsontype.Type
1103 buf []byte
1104 err error
1105 }
1106
1107 func (tvm testValueMarshaler) MarshalBSONValue() (bsontype.Type, []byte, error) {
1108 return tvm.t, tvm.buf, tvm.err
1109 }
1110
1111 type testValueUnmarshaler struct {
1112 t bsontype.Type
1113 val []byte
1114 err error
1115 }
1116
1117 func (tvu *testValueUnmarshaler) UnmarshalBSONValue(t bsontype.Type, val []byte) error {
1118 tvu.t, tvu.val = t, val
1119 return tvu.err
1120 }
1121 func (tvu testValueUnmarshaler) Equal(tvu2 testValueUnmarshaler) bool {
1122 return tvu.t == tvu2.t && bytes.Equal(tvu.val, tvu2.val)
1123 }
1124
1125 type noPrivateFields struct {
1126 a string
1127 }
1128
1129 func compareNoPrivateFields(npf1, npf2 noPrivateFields) bool {
1130 return npf1.a != npf2.a
1131 }
1132
1133 type zeroTest struct {
1134 reportZero bool
1135 }
1136
1137 func (z zeroTest) IsZero() bool { return z.reportZero }
1138
1139 func compareZeroTest(_, _ zeroTest) bool { return true }
1140
View as plain text