1
2
3
4
5
6
7 package bsoncodec
8
9 import (
10 "encoding/json"
11 "errors"
12 "fmt"
13 "math"
14 "net/url"
15 "reflect"
16 "strings"
17 "testing"
18 "time"
19
20 "github.com/google/go-cmp/cmp"
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 type myInterface interface {
29 Foo() int
30 }
31
32 type myStruct struct {
33 Val int
34 }
35
36 func (ms myStruct) Foo() int {
37 return ms.Val
38 }
39
40 func TestDefaultValueEncoders(t *testing.T) {
41 var dve DefaultValueEncoders
42 var wrong = func(string, string) string { return "wrong" }
43
44 type mybool bool
45 type myint8 int8
46 type myint16 int16
47 type myint32 int32
48 type myint64 int64
49 type myint int
50 type myuint8 uint8
51 type myuint16 uint16
52 type myuint32 uint32
53 type myuint64 uint64
54 type myuint uint
55 type myfloat32 float32
56 type myfloat64 float64
57
58 now := time.Now().Truncate(time.Millisecond)
59 pjsnum := new(json.Number)
60 *pjsnum = json.Number("3.14159")
61 d128 := primitive.NewDecimal128(12345, 67890)
62 var nilValueMarshaler *testValueMarshaler
63 var nilMarshaler *testMarshaler
64 var nilProxy *testProxy
65
66 vmStruct := struct{ V testValueMarshalPtr }{testValueMarshalPtr{t: bsontype.String, buf: []byte{0x04, 0x00, 0x00, 0x00, 'f', 'o', 'o', 0x00}}}
67 mStruct := struct{ V testMarshalPtr }{testMarshalPtr{buf: bsoncore.BuildDocument(nil, bsoncore.AppendDoubleElement(nil, "pi", 3.14159))}}
68 pStruct := struct{ V testProxyPtr }{testProxyPtr{ret: int64(1234567890)}}
69
70 type subtest struct {
71 name string
72 val interface{}
73 ectx *EncodeContext
74 llvrw *bsonrwtest.ValueReaderWriter
75 invoke bsonrwtest.Invoked
76 err error
77 }
78
79 testCases := []struct {
80 name string
81 ve ValueEncoder
82 subtests []subtest
83 }{
84 {
85 "BooleanEncodeValue",
86 ValueEncoderFunc(dve.BooleanEncodeValue),
87 []subtest{
88 {
89 "wrong type",
90 wrong,
91 nil,
92 nil,
93 bsonrwtest.Nothing,
94 ValueEncoderError{Name: "BooleanEncodeValue", Kinds: []reflect.Kind{reflect.Bool}, Received: reflect.ValueOf(wrong)},
95 },
96 {"fast path", bool(true), nil, nil, bsonrwtest.WriteBoolean, nil},
97 {"reflection path", mybool(true), nil, nil, bsonrwtest.WriteBoolean, nil},
98 },
99 },
100 {
101 "IntEncodeValue",
102 ValueEncoderFunc(dve.IntEncodeValue),
103 []subtest{
104 {
105 "wrong type",
106 wrong,
107 nil,
108 nil,
109 bsonrwtest.Nothing,
110 ValueEncoderError{
111 Name: "IntEncodeValue",
112 Kinds: []reflect.Kind{reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int},
113 Received: reflect.ValueOf(wrong),
114 },
115 },
116 {"int8/fast path", int8(127), nil, nil, bsonrwtest.WriteInt32, nil},
117 {"int16/fast path", int16(32767), nil, nil, bsonrwtest.WriteInt32, nil},
118 {"int32/fast path", int32(2147483647), nil, nil, bsonrwtest.WriteInt32, nil},
119 {"int64/fast path", int64(1234567890987), nil, nil, bsonrwtest.WriteInt64, nil},
120 {"int64/fast path - minsize", int64(math.MaxInt32), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
121 {"int64/fast path - minsize too large", int64(math.MaxInt32 + 1), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
122 {"int64/fast path - minsize too small", int64(math.MinInt32 - 1), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
123 {"int/fast path - positive int32", int(math.MaxInt32 - 1), nil, nil, bsonrwtest.WriteInt32, nil},
124 {"int/fast path - negative int32", int(math.MinInt32 + 1), nil, nil, bsonrwtest.WriteInt32, nil},
125 {"int/fast path - MaxInt32", int(math.MaxInt32), nil, nil, bsonrwtest.WriteInt32, nil},
126 {"int/fast path - MinInt32", int(math.MinInt32), nil, nil, bsonrwtest.WriteInt32, nil},
127 {"int8/reflection path", myint8(127), nil, nil, bsonrwtest.WriteInt32, nil},
128 {"int16/reflection path", myint16(32767), nil, nil, bsonrwtest.WriteInt32, nil},
129 {"int32/reflection path", myint32(2147483647), nil, nil, bsonrwtest.WriteInt32, nil},
130 {"int64/reflection path", myint64(1234567890987), nil, nil, bsonrwtest.WriteInt64, nil},
131 {"int64/reflection path - minsize", myint64(math.MaxInt32), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
132 {"int64/reflection path - minsize too large", myint64(math.MaxInt32 + 1), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
133 {"int64/reflection path - minsize too small", myint64(math.MinInt32 - 1), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
134 {"int/reflection path - positive int32", myint(math.MaxInt32 - 1), nil, nil, bsonrwtest.WriteInt32, nil},
135 {"int/reflection path - negative int32", myint(math.MinInt32 + 1), nil, nil, bsonrwtest.WriteInt32, nil},
136 {"int/reflection path - MaxInt32", myint(math.MaxInt32), nil, nil, bsonrwtest.WriteInt32, nil},
137 {"int/reflection path - MinInt32", myint(math.MinInt32), nil, nil, bsonrwtest.WriteInt32, nil},
138 },
139 },
140 {
141 "UintEncodeValue",
142 defaultUIntCodec,
143 []subtest{
144 {
145 "wrong type",
146 wrong,
147 nil,
148 nil,
149 bsonrwtest.Nothing,
150 ValueEncoderError{
151 Name: "UintEncodeValue",
152 Kinds: []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint},
153 Received: reflect.ValueOf(wrong),
154 },
155 },
156 {"uint8/fast path", uint8(127), nil, nil, bsonrwtest.WriteInt32, nil},
157 {"uint16/fast path", uint16(32767), nil, nil, bsonrwtest.WriteInt32, nil},
158 {"uint32/fast path", uint32(2147483647), nil, nil, bsonrwtest.WriteInt64, nil},
159 {"uint64/fast path", uint64(1234567890987), nil, nil, bsonrwtest.WriteInt64, nil},
160 {"uint/fast path", uint(1234567), nil, nil, bsonrwtest.WriteInt64, nil},
161 {"uint32/fast path - minsize", uint32(2147483647), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
162 {"uint64/fast path - minsize", uint64(2147483647), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
163 {"uint/fast path - minsize", uint(2147483647), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
164 {"uint32/fast path - minsize too large", uint32(2147483648), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
165 {"uint64/fast path - minsize too large", uint64(2147483648), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
166 {"uint/fast path - minsize too large", uint(2147483648), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
167 {"uint64/fast path - overflow", uint64(1 << 63), nil, nil, bsonrwtest.Nothing, fmt.Errorf("%d overflows int64", uint64(1<<63))},
168 {"uint8/reflection path", myuint8(127), nil, nil, bsonrwtest.WriteInt32, nil},
169 {"uint16/reflection path", myuint16(32767), nil, nil, bsonrwtest.WriteInt32, nil},
170 {"uint32/reflection path", myuint32(2147483647), nil, nil, bsonrwtest.WriteInt64, nil},
171 {"uint64/reflection path", myuint64(1234567890987), nil, nil, bsonrwtest.WriteInt64, nil},
172 {"uint32/reflection path - minsize", myuint32(2147483647), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
173 {"uint64/reflection path - minsize", myuint64(2147483647), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
174 {"uint/reflection path - minsize", myuint(2147483647), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
175 {"uint32/reflection path - minsize too large", myuint(1 << 31), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
176 {"uint64/reflection path - minsize too large", myuint64(1 << 31), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
177 {"uint/reflection path - minsize too large", myuint(2147483648), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
178 {"uint64/reflection path - overflow", myuint64(1 << 63), nil, nil, bsonrwtest.Nothing, fmt.Errorf("%d overflows int64", uint64(1<<63))},
179 },
180 },
181 {
182 "FloatEncodeValue",
183 ValueEncoderFunc(dve.FloatEncodeValue),
184 []subtest{
185 {
186 "wrong type",
187 wrong,
188 nil,
189 nil,
190 bsonrwtest.Nothing,
191 ValueEncoderError{
192 Name: "FloatEncodeValue",
193 Kinds: []reflect.Kind{reflect.Float32, reflect.Float64},
194 Received: reflect.ValueOf(wrong),
195 },
196 },
197 {"float32/fast path", float32(3.14159), nil, nil, bsonrwtest.WriteDouble, nil},
198 {"float64/fast path", float64(3.14159), nil, nil, bsonrwtest.WriteDouble, nil},
199 {"float32/reflection path", myfloat32(3.14159), nil, nil, bsonrwtest.WriteDouble, nil},
200 {"float64/reflection path", myfloat64(3.14159), nil, nil, bsonrwtest.WriteDouble, nil},
201 },
202 },
203 {
204 "TimeEncodeValue",
205 defaultTimeCodec,
206 []subtest{
207 {
208 "wrong type",
209 wrong,
210 nil,
211 nil,
212 bsonrwtest.Nothing,
213 ValueEncoderError{Name: "TimeEncodeValue", Types: []reflect.Type{tTime}, Received: reflect.ValueOf(wrong)},
214 },
215 {"time.Time", now, nil, nil, bsonrwtest.WriteDateTime, nil},
216 },
217 },
218 {
219 "MapEncodeValue",
220 defaultMapCodec,
221 []subtest{
222 {
223 "wrong kind",
224 wrong,
225 nil,
226 nil,
227 bsonrwtest.Nothing,
228 ValueEncoderError{Name: "MapEncodeValue", Kinds: []reflect.Kind{reflect.Map}, Received: reflect.ValueOf(wrong)},
229 },
230 {
231 "WriteDocument Error",
232 map[string]interface{}{},
233 nil,
234 &bsonrwtest.ValueReaderWriter{Err: errors.New("wd error"), ErrAfter: bsonrwtest.WriteDocument},
235 bsonrwtest.WriteDocument,
236 errors.New("wd error"),
237 },
238 {
239 "Lookup Error",
240 map[string]int{"foo": 1},
241 &EncodeContext{Registry: NewRegistryBuilder().Build()},
242 &bsonrwtest.ValueReaderWriter{},
243 bsonrwtest.WriteDocument,
244 fmt.Errorf("no encoder found for int"),
245 },
246 {
247 "WriteDocumentElement Error",
248 map[string]interface{}{"foo": "bar"},
249 &EncodeContext{Registry: buildDefaultRegistry()},
250 &bsonrwtest.ValueReaderWriter{Err: errors.New("wde error"), ErrAfter: bsonrwtest.WriteDocumentElement},
251 bsonrwtest.WriteDocumentElement,
252 errors.New("wde error"),
253 },
254 {
255 "EncodeValue Error",
256 map[string]interface{}{"foo": "bar"},
257 &EncodeContext{Registry: buildDefaultRegistry()},
258 &bsonrwtest.ValueReaderWriter{Err: errors.New("ev error"), ErrAfter: bsonrwtest.WriteString},
259 bsonrwtest.WriteString,
260 errors.New("ev error"),
261 },
262 {
263 "empty map/success",
264 map[string]interface{}{},
265 &EncodeContext{Registry: NewRegistryBuilder().Build()},
266 &bsonrwtest.ValueReaderWriter{},
267 bsonrwtest.WriteDocumentEnd,
268 nil,
269 },
270 {
271 "with interface/success",
272 map[string]myInterface{"foo": myStruct{1}},
273 &EncodeContext{Registry: buildDefaultRegistry()},
274 nil,
275 bsonrwtest.WriteDocumentEnd,
276 nil,
277 },
278 {
279 "with interface/nil/success",
280 map[string]myInterface{"foo": nil},
281 &EncodeContext{Registry: buildDefaultRegistry()},
282 nil,
283 bsonrwtest.WriteDocumentEnd,
284 nil,
285 },
286 {
287 "non-string key success",
288 map[int]interface{}{
289 1: "foobar",
290 },
291 &EncodeContext{Registry: buildDefaultRegistry()},
292 &bsonrwtest.ValueReaderWriter{},
293 bsonrwtest.WriteDocumentEnd,
294 nil,
295 },
296 },
297 },
298 {
299 "ArrayEncodeValue",
300 ValueEncoderFunc(dve.ArrayEncodeValue),
301 []subtest{
302 {
303 "wrong kind",
304 wrong,
305 nil,
306 nil,
307 bsonrwtest.Nothing,
308 ValueEncoderError{Name: "ArrayEncodeValue", Kinds: []reflect.Kind{reflect.Array}, Received: reflect.ValueOf(wrong)},
309 },
310 {
311 "WriteArray Error",
312 [1]string{},
313 nil,
314 &bsonrwtest.ValueReaderWriter{Err: errors.New("wa error"), ErrAfter: bsonrwtest.WriteArray},
315 bsonrwtest.WriteArray,
316 errors.New("wa error"),
317 },
318 {
319 "Lookup Error",
320 [1]int{1},
321 &EncodeContext{Registry: NewRegistryBuilder().Build()},
322 &bsonrwtest.ValueReaderWriter{},
323 bsonrwtest.WriteArray,
324 fmt.Errorf("no encoder found for int"),
325 },
326 {
327 "WriteArrayElement Error",
328 [1]string{"foo"},
329 &EncodeContext{Registry: buildDefaultRegistry()},
330 &bsonrwtest.ValueReaderWriter{Err: errors.New("wae error"), ErrAfter: bsonrwtest.WriteArrayElement},
331 bsonrwtest.WriteArrayElement,
332 errors.New("wae error"),
333 },
334 {
335 "EncodeValue Error",
336 [1]string{"foo"},
337 &EncodeContext{Registry: buildDefaultRegistry()},
338 &bsonrwtest.ValueReaderWriter{Err: errors.New("ev error"), ErrAfter: bsonrwtest.WriteString},
339 bsonrwtest.WriteString,
340 errors.New("ev error"),
341 },
342 {
343 "[1]primitive.E/success",
344 [1]primitive.E{{"hello", "world"}},
345 &EncodeContext{Registry: buildDefaultRegistry()},
346 nil,
347 bsonrwtest.WriteDocumentEnd,
348 nil,
349 },
350 {
351 "[1]primitive.E/success",
352 [1]primitive.E{{"hello", nil}},
353 &EncodeContext{Registry: buildDefaultRegistry()},
354 nil,
355 bsonrwtest.WriteDocumentEnd,
356 nil,
357 },
358 {
359 "[1]interface/success",
360 [1]myInterface{myStruct{1}},
361 &EncodeContext{Registry: buildDefaultRegistry()},
362 nil,
363 bsonrwtest.WriteArrayEnd,
364 nil,
365 },
366 {
367 "[1]interface/nil/success",
368 [1]myInterface{nil},
369 &EncodeContext{Registry: buildDefaultRegistry()},
370 nil,
371 bsonrwtest.WriteArrayEnd,
372 nil,
373 },
374 },
375 },
376 {
377 "SliceEncodeValue",
378 defaultSliceCodec,
379 []subtest{
380 {
381 "wrong kind",
382 wrong,
383 nil,
384 nil,
385 bsonrwtest.Nothing,
386 ValueEncoderError{Name: "SliceEncodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: reflect.ValueOf(wrong)},
387 },
388 {
389 "WriteArray Error",
390 []string{},
391 nil,
392 &bsonrwtest.ValueReaderWriter{Err: errors.New("wa error"), ErrAfter: bsonrwtest.WriteArray},
393 bsonrwtest.WriteArray,
394 errors.New("wa error"),
395 },
396 {
397 "Lookup Error",
398 []int{1},
399 &EncodeContext{Registry: NewRegistryBuilder().Build()},
400 &bsonrwtest.ValueReaderWriter{},
401 bsonrwtest.WriteArray,
402 fmt.Errorf("no encoder found for int"),
403 },
404 {
405 "WriteArrayElement Error",
406 []string{"foo"},
407 &EncodeContext{Registry: buildDefaultRegistry()},
408 &bsonrwtest.ValueReaderWriter{Err: errors.New("wae error"), ErrAfter: bsonrwtest.WriteArrayElement},
409 bsonrwtest.WriteArrayElement,
410 errors.New("wae error"),
411 },
412 {
413 "EncodeValue Error",
414 []string{"foo"},
415 &EncodeContext{Registry: buildDefaultRegistry()},
416 &bsonrwtest.ValueReaderWriter{Err: errors.New("ev error"), ErrAfter: bsonrwtest.WriteString},
417 bsonrwtest.WriteString,
418 errors.New("ev error"),
419 },
420 {
421 "D/success",
422 primitive.D{{"hello", "world"}},
423 &EncodeContext{Registry: buildDefaultRegistry()},
424 nil,
425 bsonrwtest.WriteDocumentEnd,
426 nil,
427 },
428 {
429 "D/success",
430 primitive.D{{"hello", nil}},
431 &EncodeContext{Registry: buildDefaultRegistry()},
432 nil,
433 bsonrwtest.WriteDocumentEnd,
434 nil,
435 },
436 {
437 "empty slice/success",
438 []interface{}{},
439 &EncodeContext{Registry: NewRegistryBuilder().Build()},
440 &bsonrwtest.ValueReaderWriter{},
441 bsonrwtest.WriteArrayEnd,
442 nil,
443 },
444 {
445 "interface/success",
446 []myInterface{myStruct{1}},
447 &EncodeContext{Registry: buildDefaultRegistry()},
448 nil,
449 bsonrwtest.WriteArrayEnd,
450 nil,
451 },
452 {
453 "interface/success",
454 []myInterface{nil},
455 &EncodeContext{Registry: buildDefaultRegistry()},
456 nil,
457 bsonrwtest.WriteArrayEnd,
458 nil,
459 },
460 },
461 },
462 {
463 "ObjectIDEncodeValue",
464 ValueEncoderFunc(dve.ObjectIDEncodeValue),
465 []subtest{
466 {
467 "wrong type",
468 wrong,
469 nil,
470 nil,
471 bsonrwtest.Nothing,
472 ValueEncoderError{Name: "ObjectIDEncodeValue", Types: []reflect.Type{tOID}, Received: reflect.ValueOf(wrong)},
473 },
474 {
475 "primitive.ObjectID/success",
476 primitive.ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
477 nil, nil, bsonrwtest.WriteObjectID, nil,
478 },
479 },
480 },
481 {
482 "Decimal128EncodeValue",
483 ValueEncoderFunc(dve.Decimal128EncodeValue),
484 []subtest{
485 {
486 "wrong type",
487 wrong,
488 nil,
489 nil,
490 bsonrwtest.Nothing,
491 ValueEncoderError{Name: "Decimal128EncodeValue", Types: []reflect.Type{tDecimal}, Received: reflect.ValueOf(wrong)},
492 },
493 {"Decimal128/success", d128, nil, nil, bsonrwtest.WriteDecimal128, nil},
494 },
495 },
496 {
497 "JSONNumberEncodeValue",
498 ValueEncoderFunc(dve.JSONNumberEncodeValue),
499 []subtest{
500 {
501 "wrong type",
502 wrong,
503 nil,
504 nil,
505 bsonrwtest.Nothing,
506 ValueEncoderError{Name: "JSONNumberEncodeValue", Types: []reflect.Type{tJSONNumber}, Received: reflect.ValueOf(wrong)},
507 },
508 {
509 "json.Number/invalid",
510 json.Number("hello world"),
511 nil, nil, bsonrwtest.Nothing, errors.New(`strconv.ParseFloat: parsing "hello world": invalid syntax`),
512 },
513 {
514 "json.Number/int64/success",
515 json.Number("1234567890"),
516 nil, nil, bsonrwtest.WriteInt64, nil,
517 },
518 {
519 "json.Number/float64/success",
520 json.Number("3.14159"),
521 nil, nil, bsonrwtest.WriteDouble, nil,
522 },
523 },
524 },
525 {
526 "URLEncodeValue",
527 ValueEncoderFunc(dve.URLEncodeValue),
528 []subtest{
529 {
530 "wrong type",
531 wrong,
532 nil,
533 nil,
534 bsonrwtest.Nothing,
535 ValueEncoderError{Name: "URLEncodeValue", Types: []reflect.Type{tURL}, Received: reflect.ValueOf(wrong)},
536 },
537 {"url.URL", url.URL{Scheme: "http", Host: "example.com"}, nil, nil, bsonrwtest.WriteString, nil},
538 },
539 },
540 {
541 "ByteSliceEncodeValue",
542 defaultByteSliceCodec,
543 []subtest{
544 {
545 "wrong type",
546 wrong,
547 nil,
548 nil,
549 bsonrwtest.Nothing,
550 ValueEncoderError{Name: "ByteSliceEncodeValue", Types: []reflect.Type{tByteSlice}, Received: reflect.ValueOf(wrong)},
551 },
552 {"[]byte", []byte{0x01, 0x02, 0x03}, nil, nil, bsonrwtest.WriteBinary, nil},
553 {"[]byte/nil", []byte(nil), nil, nil, bsonrwtest.WriteNull, nil},
554 },
555 },
556 {
557 "EmptyInterfaceEncodeValue",
558 defaultEmptyInterfaceCodec,
559 []subtest{
560 {
561 "wrong type",
562 wrong,
563 nil,
564 nil,
565 bsonrwtest.Nothing,
566 ValueEncoderError{Name: "EmptyInterfaceEncodeValue", Types: []reflect.Type{tEmpty}, Received: reflect.ValueOf(wrong)},
567 },
568 },
569 },
570 {
571 "ValueMarshalerEncodeValue",
572 ValueEncoderFunc(dve.ValueMarshalerEncodeValue),
573 []subtest{
574 {
575 "wrong type",
576 wrong,
577 nil,
578 nil,
579 bsonrwtest.Nothing,
580 ValueEncoderError{
581 Name: "ValueMarshalerEncodeValue",
582 Types: []reflect.Type{tValueMarshaler},
583 Received: reflect.ValueOf(wrong),
584 },
585 },
586 {
587 "MarshalBSONValue error",
588 testValueMarshaler{err: errors.New("mbsonv error")},
589 nil,
590 nil,
591 bsonrwtest.Nothing,
592 errors.New("mbsonv error"),
593 },
594 {
595 "Copy error",
596 testValueMarshaler{},
597 nil,
598 nil,
599 bsonrwtest.Nothing,
600 fmt.Errorf("Cannot copy unknown BSON type %s", bsontype.Type(0)),
601 },
602 {
603 "success struct implementation",
604 testValueMarshaler{t: bsontype.String, buf: []byte{0x04, 0x00, 0x00, 0x00, 'f', 'o', 'o', 0x00}},
605 nil,
606 nil,
607 bsonrwtest.WriteString,
608 nil,
609 },
610 {
611 "success ptr to struct implementation",
612 &testValueMarshaler{t: bsontype.String, buf: []byte{0x04, 0x00, 0x00, 0x00, 'f', 'o', 'o', 0x00}},
613 nil,
614 nil,
615 bsonrwtest.WriteString,
616 nil,
617 },
618 {
619 "success nil ptr to struct implementation",
620 nilValueMarshaler,
621 nil,
622 nil,
623 bsonrwtest.WriteNull,
624 nil,
625 },
626 {
627 "success ptr to ptr implementation",
628 &testValueMarshalPtr{t: bsontype.String, buf: []byte{0x04, 0x00, 0x00, 0x00, 'f', 'o', 'o', 0x00}},
629 nil,
630 nil,
631 bsonrwtest.WriteString,
632 nil,
633 },
634 {
635 "unaddressable ptr implementation",
636 testValueMarshalPtr{t: bsontype.String, buf: []byte{0x04, 0x00, 0x00, 0x00, 'f', 'o', 'o', 0x00}},
637 nil,
638 nil,
639 bsonrwtest.Nothing,
640 ValueEncoderError{
641 Name: "ValueMarshalerEncodeValue",
642 Types: []reflect.Type{tValueMarshaler},
643 Received: reflect.ValueOf(testValueMarshalPtr{}),
644 },
645 },
646 },
647 },
648 {
649 "MarshalerEncodeValue",
650 ValueEncoderFunc(dve.MarshalerEncodeValue),
651 []subtest{
652 {
653 "wrong type",
654 wrong,
655 nil,
656 nil,
657 bsonrwtest.Nothing,
658 ValueEncoderError{Name: "MarshalerEncodeValue", Types: []reflect.Type{tMarshaler}, Received: reflect.ValueOf(wrong)},
659 },
660 {
661 "MarshalBSON error",
662 testMarshaler{err: errors.New("mbson error")},
663 nil,
664 nil,
665 bsonrwtest.Nothing,
666 errors.New("mbson error"),
667 },
668 {
669 "success struct implementation",
670 testMarshaler{buf: bsoncore.BuildDocument(nil, bsoncore.AppendDoubleElement(nil, "pi", 3.14159))},
671 nil,
672 nil,
673 bsonrwtest.WriteDocumentEnd,
674 nil,
675 },
676 {
677 "success ptr to struct implementation",
678 &testMarshaler{buf: bsoncore.BuildDocument(nil, bsoncore.AppendDoubleElement(nil, "pi", 3.14159))},
679 nil,
680 nil,
681 bsonrwtest.WriteDocumentEnd,
682 nil,
683 },
684 {
685 "success nil ptr to struct implementation",
686 nilMarshaler,
687 nil,
688 nil,
689 bsonrwtest.WriteNull,
690 nil,
691 },
692 {
693 "success ptr to ptr implementation",
694 &testMarshalPtr{buf: bsoncore.BuildDocument(nil, bsoncore.AppendDoubleElement(nil, "pi", 3.14159))},
695 nil,
696 nil,
697 bsonrwtest.WriteDocumentEnd,
698 nil,
699 },
700 {
701 "unaddressable ptr implementation",
702 testMarshalPtr{buf: bsoncore.BuildDocument(nil, bsoncore.AppendDoubleElement(nil, "pi", 3.14159))},
703 nil,
704 nil,
705 bsonrwtest.Nothing,
706 ValueEncoderError{Name: "MarshalerEncodeValue", Types: []reflect.Type{tMarshaler}, Received: reflect.ValueOf(testMarshalPtr{})},
707 },
708 },
709 },
710 {
711 "ProxyEncodeValue",
712 ValueEncoderFunc(dve.ProxyEncodeValue),
713 []subtest{
714 {
715 "wrong type",
716 wrong,
717 nil,
718 nil,
719 bsonrwtest.Nothing,
720 ValueEncoderError{Name: "ProxyEncodeValue", Types: []reflect.Type{tProxy}, Received: reflect.ValueOf(wrong)},
721 },
722 {
723 "Proxy error",
724 testProxy{err: errors.New("proxy error")},
725 nil,
726 nil,
727 bsonrwtest.Nothing,
728 errors.New("proxy error"),
729 },
730 {
731 "Lookup error",
732 testProxy{ret: nil},
733 &EncodeContext{Registry: buildDefaultRegistry()},
734 nil,
735 bsonrwtest.Nothing,
736 ErrNoEncoder{Type: nil},
737 },
738 {
739 "success struct implementation",
740 testProxy{ret: int64(1234567890)},
741 &EncodeContext{Registry: buildDefaultRegistry()},
742 nil,
743 bsonrwtest.WriteInt64,
744 nil,
745 },
746 {
747 "success ptr to struct implementation",
748 &testProxy{ret: int64(1234567890)},
749 &EncodeContext{Registry: buildDefaultRegistry()},
750 nil,
751 bsonrwtest.WriteInt64,
752 nil,
753 },
754 {
755 "success nil ptr to struct implementation",
756 nilProxy,
757 nil,
758 nil,
759 bsonrwtest.WriteNull,
760 nil,
761 },
762 {
763 "success ptr to ptr implementation",
764 &testProxyPtr{ret: int64(1234567890)},
765 &EncodeContext{Registry: buildDefaultRegistry()},
766 nil,
767 bsonrwtest.WriteInt64,
768 nil,
769 },
770 {
771 "unaddressable ptr implementation",
772 testProxyPtr{ret: int64(1234567890)},
773 nil,
774 nil,
775 bsonrwtest.Nothing,
776 ValueEncoderError{Name: "ProxyEncodeValue", Types: []reflect.Type{tProxy}, Received: reflect.ValueOf(testProxyPtr{})},
777 },
778 },
779 },
780 {
781 "PointerCodec.EncodeValue",
782 NewPointerCodec(),
783 []subtest{
784 {
785 "nil",
786 nil,
787 nil,
788 nil,
789 bsonrwtest.WriteNull,
790 nil,
791 },
792 {
793 "not pointer",
794 int32(123456),
795 nil,
796 nil,
797 bsonrwtest.Nothing,
798 ValueEncoderError{Name: "PointerCodec.EncodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: reflect.ValueOf(int32(123456))},
799 },
800 {
801 "typed nil",
802 (*int32)(nil),
803 nil,
804 nil,
805 bsonrwtest.WriteNull,
806 nil,
807 },
808 {
809 "no encoder",
810 &wrong,
811 &EncodeContext{Registry: buildDefaultRegistry()},
812 nil,
813 bsonrwtest.Nothing,
814 ErrNoEncoder{Type: reflect.TypeOf(wrong)},
815 },
816 },
817 },
818 {
819 "pointer implementation addressable interface",
820 NewPointerCodec(),
821 []subtest{
822 {
823 "ValueMarshaler",
824 &vmStruct,
825 &EncodeContext{Registry: buildDefaultRegistry()},
826 nil,
827 bsonrwtest.WriteDocumentEnd,
828 nil,
829 },
830 {
831 "Marshaler",
832 &mStruct,
833 &EncodeContext{Registry: buildDefaultRegistry()},
834 nil,
835 bsonrwtest.WriteDocumentEnd,
836 nil,
837 },
838 {
839 "Proxy",
840 &pStruct,
841 &EncodeContext{Registry: buildDefaultRegistry()},
842 nil,
843 bsonrwtest.WriteDocumentEnd,
844 nil,
845 },
846 },
847 },
848 {
849 "JavaScriptEncodeValue",
850 ValueEncoderFunc(dve.JavaScriptEncodeValue),
851 []subtest{
852 {
853 "wrong type",
854 wrong,
855 nil,
856 nil,
857 bsonrwtest.Nothing,
858 ValueEncoderError{Name: "JavaScriptEncodeValue", Types: []reflect.Type{tJavaScript}, Received: reflect.ValueOf(wrong)},
859 },
860 {"JavaScript", primitive.JavaScript("foobar"), nil, nil, bsonrwtest.WriteJavascript, nil},
861 },
862 },
863 {
864 "SymbolEncodeValue",
865 ValueEncoderFunc(dve.SymbolEncodeValue),
866 []subtest{
867 {
868 "wrong type",
869 wrong,
870 nil,
871 nil,
872 bsonrwtest.Nothing,
873 ValueEncoderError{Name: "SymbolEncodeValue", Types: []reflect.Type{tSymbol}, Received: reflect.ValueOf(wrong)},
874 },
875 {"Symbol", primitive.Symbol("foobar"), nil, nil, bsonrwtest.WriteSymbol, nil},
876 },
877 },
878 {
879 "BinaryEncodeValue",
880 ValueEncoderFunc(dve.BinaryEncodeValue),
881 []subtest{
882 {
883 "wrong type",
884 wrong,
885 nil,
886 nil,
887 bsonrwtest.Nothing,
888 ValueEncoderError{Name: "BinaryEncodeValue", Types: []reflect.Type{tBinary}, Received: reflect.ValueOf(wrong)},
889 },
890 {"Binary/success", primitive.Binary{Data: []byte{0x01, 0x02}, Subtype: 0xFF}, nil, nil, bsonrwtest.WriteBinaryWithSubtype, nil},
891 },
892 },
893 {
894 "UndefinedEncodeValue",
895 ValueEncoderFunc(dve.UndefinedEncodeValue),
896 []subtest{
897 {
898 "wrong type",
899 wrong,
900 nil,
901 nil,
902 bsonrwtest.Nothing,
903 ValueEncoderError{Name: "UndefinedEncodeValue", Types: []reflect.Type{tUndefined}, Received: reflect.ValueOf(wrong)},
904 },
905 {"Undefined/success", primitive.Undefined{}, nil, nil, bsonrwtest.WriteUndefined, nil},
906 },
907 },
908 {
909 "DateTimeEncodeValue",
910 ValueEncoderFunc(dve.DateTimeEncodeValue),
911 []subtest{
912 {
913 "wrong type",
914 wrong,
915 nil,
916 nil,
917 bsonrwtest.Nothing,
918 ValueEncoderError{Name: "DateTimeEncodeValue", Types: []reflect.Type{tDateTime}, Received: reflect.ValueOf(wrong)},
919 },
920 {"DateTime/success", primitive.DateTime(1234567890), nil, nil, bsonrwtest.WriteDateTime, nil},
921 },
922 },
923 {
924 "NullEncodeValue",
925 ValueEncoderFunc(dve.NullEncodeValue),
926 []subtest{
927 {
928 "wrong type",
929 wrong,
930 nil,
931 nil,
932 bsonrwtest.Nothing,
933 ValueEncoderError{Name: "NullEncodeValue", Types: []reflect.Type{tNull}, Received: reflect.ValueOf(wrong)},
934 },
935 {"Null/success", primitive.Null{}, nil, nil, bsonrwtest.WriteNull, nil},
936 },
937 },
938 {
939 "RegexEncodeValue",
940 ValueEncoderFunc(dve.RegexEncodeValue),
941 []subtest{
942 {
943 "wrong type",
944 wrong,
945 nil,
946 nil,
947 bsonrwtest.Nothing,
948 ValueEncoderError{Name: "RegexEncodeValue", Types: []reflect.Type{tRegex}, Received: reflect.ValueOf(wrong)},
949 },
950 {"Regex/success", primitive.Regex{Pattern: "foo", Options: "bar"}, nil, nil, bsonrwtest.WriteRegex, nil},
951 },
952 },
953 {
954 "DBPointerEncodeValue",
955 ValueEncoderFunc(dve.DBPointerEncodeValue),
956 []subtest{
957 {
958 "wrong type",
959 wrong,
960 nil,
961 nil,
962 bsonrwtest.Nothing,
963 ValueEncoderError{Name: "DBPointerEncodeValue", Types: []reflect.Type{tDBPointer}, Received: reflect.ValueOf(wrong)},
964 },
965 {
966 "DBPointer/success",
967 primitive.DBPointer{
968 DB: "foobar",
969 Pointer: primitive.ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
970 },
971 nil, nil, bsonrwtest.WriteDBPointer, nil,
972 },
973 },
974 },
975 {
976 "TimestampEncodeValue",
977 ValueEncoderFunc(dve.TimestampEncodeValue),
978 []subtest{
979 {
980 "wrong type",
981 wrong,
982 nil,
983 nil,
984 bsonrwtest.Nothing,
985 ValueEncoderError{Name: "TimestampEncodeValue", Types: []reflect.Type{tTimestamp}, Received: reflect.ValueOf(wrong)},
986 },
987 {"Timestamp/success", primitive.Timestamp{T: 12345, I: 67890}, nil, nil, bsonrwtest.WriteTimestamp, nil},
988 },
989 },
990 {
991 "MinKeyEncodeValue",
992 ValueEncoderFunc(dve.MinKeyEncodeValue),
993 []subtest{
994 {
995 "wrong type",
996 wrong,
997 nil,
998 nil,
999 bsonrwtest.Nothing,
1000 ValueEncoderError{Name: "MinKeyEncodeValue", Types: []reflect.Type{tMinKey}, Received: reflect.ValueOf(wrong)},
1001 },
1002 {"MinKey/success", primitive.MinKey{}, nil, nil, bsonrwtest.WriteMinKey, nil},
1003 },
1004 },
1005 {
1006 "MaxKeyEncodeValue",
1007 ValueEncoderFunc(dve.MaxKeyEncodeValue),
1008 []subtest{
1009 {
1010 "wrong type",
1011 wrong,
1012 nil,
1013 nil,
1014 bsonrwtest.Nothing,
1015 ValueEncoderError{Name: "MaxKeyEncodeValue", Types: []reflect.Type{tMaxKey}, Received: reflect.ValueOf(wrong)},
1016 },
1017 {"MaxKey/success", primitive.MaxKey{}, nil, nil, bsonrwtest.WriteMaxKey, nil},
1018 },
1019 },
1020 {
1021 "CoreDocumentEncodeValue",
1022 ValueEncoderFunc(dve.CoreDocumentEncodeValue),
1023 []subtest{
1024 {
1025 "wrong type",
1026 wrong,
1027 nil,
1028 nil,
1029 bsonrwtest.Nothing,
1030 ValueEncoderError{
1031 Name: "CoreDocumentEncodeValue",
1032 Types: []reflect.Type{tCoreDocument},
1033 Received: reflect.ValueOf(wrong),
1034 },
1035 },
1036 {
1037 "WriteDocument Error",
1038 bsoncore.Document{},
1039 nil,
1040 &bsonrwtest.ValueReaderWriter{Err: errors.New("wd error"), ErrAfter: bsonrwtest.WriteDocument},
1041 bsonrwtest.WriteDocument,
1042 errors.New("wd error"),
1043 },
1044 {
1045 "bsoncore.Document.Elements Error",
1046 bsoncore.Document{0xFF, 0x00, 0x00, 0x00, 0x00},
1047 nil,
1048 &bsonrwtest.ValueReaderWriter{},
1049 bsonrwtest.WriteDocument,
1050 errors.New("length read exceeds number of bytes available. length=5 bytes=255"),
1051 },
1052 {
1053 "WriteDocumentElement Error",
1054 bsoncore.Document(buildDocument(bsoncore.AppendNullElement(nil, "foo"))),
1055 nil,
1056 &bsonrwtest.ValueReaderWriter{Err: errors.New("wde error"), ErrAfter: bsonrwtest.WriteDocumentElement},
1057 bsonrwtest.WriteDocumentElement,
1058 errors.New("wde error"),
1059 },
1060 {
1061 "encodeValue error",
1062 bsoncore.Document(buildDocument(bsoncore.AppendNullElement(nil, "foo"))),
1063 nil,
1064 &bsonrwtest.ValueReaderWriter{Err: errors.New("ev error"), ErrAfter: bsonrwtest.WriteNull},
1065 bsonrwtest.WriteNull,
1066 errors.New("ev error"),
1067 },
1068 {
1069 "iterator error",
1070 bsoncore.Document{0x0C, 0x00, 0x00, 0x00, 0x01, 'f', 'o', 'o', 0x00, 0x01, 0x02, 0x03},
1071 nil,
1072 &bsonrwtest.ValueReaderWriter{},
1073 bsonrwtest.WriteDocumentElement,
1074 errors.New("not enough bytes available to read type. bytes=3 type=double"),
1075 },
1076 },
1077 },
1078 {
1079 "StructEncodeValue",
1080 defaultTestStructCodec,
1081 []subtest{
1082 {
1083 "interface value",
1084 struct{ Foo myInterface }{Foo: myStruct{1}},
1085 &EncodeContext{Registry: buildDefaultRegistry()},
1086 nil,
1087 bsonrwtest.WriteDocumentEnd,
1088 nil,
1089 },
1090 {
1091 "nil interface value",
1092 struct{ Foo myInterface }{Foo: nil},
1093 &EncodeContext{Registry: buildDefaultRegistry()},
1094 nil,
1095 bsonrwtest.WriteDocumentEnd,
1096 nil,
1097 },
1098 },
1099 },
1100 {
1101 "CodeWithScopeEncodeValue",
1102 ValueEncoderFunc(dve.CodeWithScopeEncodeValue),
1103 []subtest{
1104 {
1105 "wrong type",
1106 wrong,
1107 nil,
1108 nil,
1109 bsonrwtest.Nothing,
1110 ValueEncoderError{
1111 Name: "CodeWithScopeEncodeValue",
1112 Types: []reflect.Type{tCodeWithScope},
1113 Received: reflect.ValueOf(wrong),
1114 },
1115 },
1116 {
1117 "WriteCodeWithScope error",
1118 primitive.CodeWithScope{},
1119 nil,
1120 &bsonrwtest.ValueReaderWriter{Err: errors.New("wcws error"), ErrAfter: bsonrwtest.WriteCodeWithScope},
1121 bsonrwtest.WriteCodeWithScope,
1122 errors.New("wcws error"),
1123 },
1124 {
1125 "CodeWithScope/success",
1126 primitive.CodeWithScope{
1127 Code: "var hello = 'world';",
1128 Scope: primitive.D{},
1129 },
1130 &EncodeContext{Registry: buildDefaultRegistry()},
1131 nil, bsonrwtest.WriteDocumentEnd, nil,
1132 },
1133 },
1134 },
1135 {
1136 "CoreArrayEncodeValue",
1137 defaultArrayCodec,
1138 []subtest{
1139 {
1140 "wrong type",
1141 wrong,
1142 nil,
1143 nil,
1144 bsonrwtest.Nothing,
1145 ValueEncoderError{
1146 Name: "CoreArrayEncodeValue",
1147 Types: []reflect.Type{tCoreArray},
1148 Received: reflect.ValueOf(wrong),
1149 },
1150 },
1151
1152 {
1153 "WriteArray Error",
1154 bsoncore.Array{},
1155 nil,
1156 &bsonrwtest.ValueReaderWriter{Err: errors.New("wa error"), ErrAfter: bsonrwtest.WriteArray},
1157 bsonrwtest.WriteArray,
1158 errors.New("wa error"),
1159 },
1160 {
1161 "WriteArrayElement Error",
1162 bsoncore.Array(buildDocumentArray(func(doc []byte) []byte {
1163 return bsoncore.AppendNullElement(nil, "foo")
1164 })),
1165 nil,
1166 &bsonrwtest.ValueReaderWriter{Err: errors.New("wae error"), ErrAfter: bsonrwtest.WriteArrayElement},
1167 bsonrwtest.WriteArrayElement,
1168 errors.New("wae error"),
1169 },
1170 {
1171 "encodeValue error",
1172 bsoncore.Array(buildDocumentArray(func(doc []byte) []byte {
1173 return bsoncore.AppendNullElement(nil, "foo")
1174 })),
1175 nil,
1176 &bsonrwtest.ValueReaderWriter{Err: errors.New("ev error"), ErrAfter: bsonrwtest.WriteNull},
1177 bsonrwtest.WriteNull,
1178 errors.New("ev error"),
1179 },
1180 },
1181 },
1182 }
1183
1184 for _, tc := range testCases {
1185 t.Run(tc.name, func(t *testing.T) {
1186 for _, subtest := range tc.subtests {
1187 t.Run(subtest.name, func(t *testing.T) {
1188 var ec EncodeContext
1189 if subtest.ectx != nil {
1190 ec = *subtest.ectx
1191 }
1192 llvrw := new(bsonrwtest.ValueReaderWriter)
1193 if subtest.llvrw != nil {
1194 llvrw = subtest.llvrw
1195 }
1196 llvrw.T = t
1197 err := tc.ve.EncodeValue(ec, llvrw, reflect.ValueOf(subtest.val))
1198 if !compareErrors(err, subtest.err) {
1199 t.Errorf("Errors do not match. got %v; want %v", err, subtest.err)
1200 }
1201 invoked := llvrw.Invoked
1202 if !cmp.Equal(invoked, subtest.invoke) {
1203 t.Errorf("Incorrect method invoked. got %v; want %v", invoked, subtest.invoke)
1204 }
1205 })
1206 }
1207 })
1208 }
1209
1210 t.Run("success path", func(t *testing.T) {
1211 oid := primitive.NewObjectID()
1212 oids := []primitive.ObjectID{primitive.NewObjectID(), primitive.NewObjectID(), primitive.NewObjectID()}
1213 var str = new(string)
1214 *str = "bar"
1215 now := time.Now().Truncate(time.Millisecond)
1216 murl, err := url.Parse("https://mongodb.com/random-url?hello=world")
1217 if err != nil {
1218 t.Errorf("Error parsing URL: %v", err)
1219 t.FailNow()
1220 }
1221 decimal128, err := primitive.ParseDecimal128("1.5e10")
1222 if err != nil {
1223 t.Errorf("Error parsing decimal128: %v", err)
1224 t.FailNow()
1225 }
1226
1227 testCases := []struct {
1228 name string
1229 value interface{}
1230 b []byte
1231 err error
1232 }{
1233 {
1234 "map[string]int",
1235 map[string]int32{"foo": 1},
1236 []byte{
1237 0x0E, 0x00, 0x00, 0x00,
1238 0x10, 'f', 'o', 'o', 0x00,
1239 0x01, 0x00, 0x00, 0x00,
1240 0x00,
1241 },
1242 nil,
1243 },
1244 {
1245 "map[string]primitive.ObjectID",
1246 map[string]primitive.ObjectID{"foo": oid},
1247 buildDocument(bsoncore.AppendObjectIDElement(nil, "foo", oid)),
1248 nil,
1249 },
1250 {
1251 "map[string][]int32",
1252 map[string][]int32{"Z": {1, 2, 3}},
1253 buildDocumentArray(func(doc []byte) []byte {
1254 doc = bsoncore.AppendInt32Element(doc, "0", 1)
1255 doc = bsoncore.AppendInt32Element(doc, "1", 2)
1256 return bsoncore.AppendInt32Element(doc, "2", 3)
1257 }),
1258 nil,
1259 },
1260 {
1261 "map[string][]primitive.ObjectID",
1262 map[string][]primitive.ObjectID{"Z": oids},
1263 buildDocumentArray(func(doc []byte) []byte {
1264 doc = bsoncore.AppendObjectIDElement(doc, "0", oids[0])
1265 doc = bsoncore.AppendObjectIDElement(doc, "1", oids[1])
1266 return bsoncore.AppendObjectIDElement(doc, "2", oids[2])
1267 }),
1268 nil,
1269 },
1270 {
1271 "map[string][]json.Number(int64)",
1272 map[string][]json.Number{"Z": {json.Number("5"), json.Number("10")}},
1273 buildDocumentArray(func(doc []byte) []byte {
1274 doc = bsoncore.AppendInt64Element(doc, "0", 5)
1275 return bsoncore.AppendInt64Element(doc, "1", 10)
1276 }),
1277 nil,
1278 },
1279 {
1280 "map[string][]json.Number(float64)",
1281 map[string][]json.Number{"Z": {json.Number("5"), json.Number("10.1")}},
1282 buildDocumentArray(func(doc []byte) []byte {
1283 doc = bsoncore.AppendInt64Element(doc, "0", 5)
1284 return bsoncore.AppendDoubleElement(doc, "1", 10.1)
1285 }),
1286 nil,
1287 },
1288 {
1289 "map[string][]*url.URL",
1290 map[string][]*url.URL{"Z": {murl}},
1291 buildDocumentArray(func(doc []byte) []byte {
1292 return bsoncore.AppendStringElement(doc, "0", murl.String())
1293 }),
1294 nil,
1295 },
1296 {
1297 "map[string][]primitive.Decimal128",
1298 map[string][]primitive.Decimal128{"Z": {decimal128}},
1299 buildDocumentArray(func(doc []byte) []byte {
1300 return bsoncore.AppendDecimal128Element(doc, "0", decimal128)
1301 }),
1302 nil,
1303 },
1304 {
1305 "-",
1306 struct {
1307 A string `bson:"-"`
1308 }{
1309 A: "",
1310 },
1311 []byte{0x05, 0x00, 0x00, 0x00, 0x00},
1312 nil,
1313 },
1314 {
1315 "omitempty",
1316 struct {
1317 A string `bson:",omitempty"`
1318 }{
1319 A: "",
1320 },
1321 []byte{0x05, 0x00, 0x00, 0x00, 0x00},
1322 nil,
1323 },
1324 {
1325 "omitempty, empty time",
1326 struct {
1327 A time.Time `bson:",omitempty"`
1328 }{
1329 A: time.Time{},
1330 },
1331 []byte{0x05, 0x00, 0x00, 0x00, 0x00},
1332 nil,
1333 },
1334 {
1335 "no private fields",
1336 noPrivateFields{a: "should be empty"},
1337 []byte{0x05, 0x00, 0x00, 0x00, 0x00},
1338 nil,
1339 },
1340 {
1341 "minsize",
1342 struct {
1343 A int64 `bson:",minsize"`
1344 }{
1345 A: 12345,
1346 },
1347 buildDocument(bsoncore.AppendInt32Element(nil, "a", 12345)),
1348 nil,
1349 },
1350 {
1351 "inline",
1352 struct {
1353 Foo struct {
1354 A int64 `bson:",minsize"`
1355 } `bson:",inline"`
1356 }{
1357 Foo: struct {
1358 A int64 `bson:",minsize"`
1359 }{
1360 A: 12345,
1361 },
1362 },
1363 buildDocument(bsoncore.AppendInt32Element(nil, "a", 12345)),
1364 nil,
1365 },
1366 {
1367 "inline struct pointer",
1368 struct {
1369 Foo *struct {
1370 A int64 `bson:",minsize"`
1371 } `bson:",inline"`
1372 Bar *struct {
1373 B int64
1374 } `bson:",inline"`
1375 }{
1376 Foo: &struct {
1377 A int64 `bson:",minsize"`
1378 }{
1379 A: 12345,
1380 },
1381 Bar: nil,
1382 },
1383 buildDocument(bsoncore.AppendInt32Element(nil, "a", 12345)),
1384 nil,
1385 },
1386 {
1387 "nested inline struct pointer",
1388 struct {
1389 Foo *struct {
1390 Bar *struct {
1391 A int64 `bson:",minsize"`
1392 } `bson:",inline"`
1393 } `bson:",inline"`
1394 }{
1395 Foo: &struct {
1396 Bar *struct {
1397 A int64 `bson:",minsize"`
1398 } `bson:",inline"`
1399 }{
1400 Bar: &struct {
1401 A int64 `bson:",minsize"`
1402 }{
1403 A: 12345,
1404 },
1405 },
1406 },
1407 buildDocument(bsoncore.AppendInt32Element(nil, "a", 12345)),
1408 nil,
1409 },
1410 {
1411 "inline nil struct pointer",
1412 struct {
1413 Foo *struct {
1414 A int64 `bson:",minsize"`
1415 } `bson:",inline"`
1416 }{
1417 Foo: nil,
1418 },
1419 buildDocument([]byte{}),
1420 nil,
1421 },
1422 {
1423 "inline overwrite",
1424 struct {
1425 Foo struct {
1426 A int32
1427 B string
1428 } `bson:",inline"`
1429 A int64
1430 }{
1431 Foo: struct {
1432 A int32
1433 B string
1434 }{
1435 A: 0,
1436 B: "foo",
1437 },
1438 A: 54321,
1439 },
1440 buildDocument(func(doc []byte) []byte {
1441 doc = bsoncore.AppendStringElement(doc, "b", "foo")
1442 doc = bsoncore.AppendInt64Element(doc, "a", 54321)
1443 return doc
1444 }(nil)),
1445 nil,
1446 },
1447 {
1448 "inline overwrite respects ordering",
1449 struct {
1450 A int64
1451 Foo struct {
1452 A int32
1453 B string
1454 } `bson:",inline"`
1455 }{
1456 A: 54321,
1457 Foo: struct {
1458 A int32
1459 B string
1460 }{
1461 A: 0,
1462 B: "foo",
1463 },
1464 },
1465 buildDocument(func(doc []byte) []byte {
1466 doc = bsoncore.AppendInt64Element(doc, "a", 54321)
1467 doc = bsoncore.AppendStringElement(doc, "b", "foo")
1468 return doc
1469 }(nil)),
1470 nil,
1471 },
1472 {
1473 "inline overwrite with nested structs",
1474 struct {
1475 Foo struct {
1476 A int32
1477 } `bson:",inline"`
1478 Bar struct {
1479 A int32
1480 } `bson:",inline"`
1481 A int64
1482 }{
1483 Foo: struct {
1484 A int32
1485 }{},
1486 Bar: struct {
1487 A int32
1488 }{},
1489 A: 54321,
1490 },
1491 buildDocument(bsoncore.AppendInt64Element(nil, "a", 54321)),
1492 nil,
1493 },
1494 {
1495 "inline map",
1496 struct {
1497 Foo map[string]string `bson:",inline"`
1498 }{
1499 Foo: map[string]string{"foo": "bar"},
1500 },
1501 buildDocument(bsoncore.AppendStringElement(nil, "foo", "bar")),
1502 nil,
1503 },
1504 {
1505 "alternate name bson:name",
1506 struct {
1507 A string `bson:"foo"`
1508 }{
1509 A: "bar",
1510 },
1511 buildDocument(bsoncore.AppendStringElement(nil, "foo", "bar")),
1512 nil,
1513 },
1514 {
1515 "alternate name",
1516 struct {
1517 A string `bson:"foo"`
1518 }{
1519 A: "bar",
1520 },
1521 buildDocument(bsoncore.AppendStringElement(nil, "foo", "bar")),
1522 nil,
1523 },
1524 {
1525 "inline, omitempty",
1526 struct {
1527 A string
1528 Foo zeroTest `bson:"omitempty,inline"`
1529 }{
1530 A: "bar",
1531 Foo: zeroTest{true},
1532 },
1533 buildDocument(bsoncore.AppendStringElement(nil, "a", "bar")),
1534 nil,
1535 },
1536 {
1537 "struct{}",
1538 struct {
1539 A bool
1540 B int32
1541 C int64
1542 D uint16
1543 E uint64
1544 F float64
1545 G string
1546 H map[string]string
1547 I []byte
1548 K [2]string
1549 L struct {
1550 M string
1551 }
1552 Q primitive.ObjectID
1553 T []struct{}
1554 Y json.Number
1555 Z time.Time
1556 AA json.Number
1557 AB *url.URL
1558 AC primitive.Decimal128
1559 AD *time.Time
1560 AE testValueMarshaler
1561 AF Proxy
1562 AG testProxy
1563 AH map[string]interface{}
1564 AI primitive.CodeWithScope
1565 }{
1566 A: true,
1567 B: 123,
1568 C: 456,
1569 D: 789,
1570 E: 101112,
1571 F: 3.14159,
1572 G: "Hello, world",
1573 H: map[string]string{"foo": "bar"},
1574 I: []byte{0x01, 0x02, 0x03},
1575 K: [2]string{"baz", "qux"},
1576 L: struct {
1577 M string
1578 }{
1579 M: "foobar",
1580 },
1581 Q: oid,
1582 T: nil,
1583 Y: json.Number("5"),
1584 Z: now,
1585 AA: json.Number("10.1"),
1586 AB: murl,
1587 AC: decimal128,
1588 AD: &now,
1589 AE: testValueMarshaler{t: bsontype.String, buf: bsoncore.AppendString(nil, "hello, world")},
1590 AF: testProxy{ret: struct{ Hello string }{Hello: "world!"}},
1591 AG: testProxy{ret: struct{ Pi float64 }{Pi: 3.14159}},
1592 AH: nil,
1593 AI: primitive.CodeWithScope{Code: "var hello = 'world';", Scope: primitive.D{{"pi", 3.14159}}},
1594 },
1595 buildDocument(func(doc []byte) []byte {
1596 doc = bsoncore.AppendBooleanElement(doc, "a", true)
1597 doc = bsoncore.AppendInt32Element(doc, "b", 123)
1598 doc = bsoncore.AppendInt64Element(doc, "c", 456)
1599 doc = bsoncore.AppendInt32Element(doc, "d", 789)
1600 doc = bsoncore.AppendInt64Element(doc, "e", 101112)
1601 doc = bsoncore.AppendDoubleElement(doc, "f", 3.14159)
1602 doc = bsoncore.AppendStringElement(doc, "g", "Hello, world")
1603 doc = bsoncore.AppendDocumentElement(doc, "h", buildDocument(bsoncore.AppendStringElement(nil, "foo", "bar")))
1604 doc = bsoncore.AppendBinaryElement(doc, "i", 0x00, []byte{0x01, 0x02, 0x03})
1605 doc = bsoncore.AppendArrayElement(doc, "k",
1606 buildArray(bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "baz"), "1", "qux")),
1607 )
1608 doc = bsoncore.AppendDocumentElement(doc, "l", buildDocument(bsoncore.AppendStringElement(nil, "m", "foobar")))
1609 doc = bsoncore.AppendObjectIDElement(doc, "q", oid)
1610 doc = bsoncore.AppendNullElement(doc, "t")
1611 doc = bsoncore.AppendInt64Element(doc, "y", 5)
1612 doc = bsoncore.AppendDateTimeElement(doc, "z", now.UnixNano()/int64(time.Millisecond))
1613 doc = bsoncore.AppendDoubleElement(doc, "aa", 10.1)
1614 doc = bsoncore.AppendStringElement(doc, "ab", murl.String())
1615 doc = bsoncore.AppendDecimal128Element(doc, "ac", decimal128)
1616 doc = bsoncore.AppendDateTimeElement(doc, "ad", now.UnixNano()/int64(time.Millisecond))
1617 doc = bsoncore.AppendStringElement(doc, "ae", "hello, world")
1618 doc = bsoncore.AppendDocumentElement(doc, "af", buildDocument(bsoncore.AppendStringElement(nil, "hello", "world!")))
1619 doc = bsoncore.AppendDocumentElement(doc, "ag", buildDocument(bsoncore.AppendDoubleElement(nil, "pi", 3.14159)))
1620 doc = bsoncore.AppendNullElement(doc, "ah")
1621 doc = bsoncore.AppendCodeWithScopeElement(doc, "ai",
1622 "var hello = 'world';", buildDocument(bsoncore.AppendDoubleElement(nil, "pi", 3.14159)),
1623 )
1624 return doc
1625 }(nil)),
1626 nil,
1627 },
1628 {
1629 "struct{[]interface{}}",
1630 struct {
1631 A []bool
1632 B []int32
1633 C []int64
1634 D []uint16
1635 E []uint64
1636 F []float64
1637 G []string
1638 H []map[string]string
1639 I [][]byte
1640 K [1][2]string
1641 L []struct {
1642 M string
1643 }
1644 N [][]string
1645 R []primitive.ObjectID
1646 T []struct{}
1647 W []map[string]struct{}
1648 X []map[string]struct{}
1649 Y []map[string]struct{}
1650 Z []time.Time
1651 AA []json.Number
1652 AB []*url.URL
1653 AC []primitive.Decimal128
1654 AD []*time.Time
1655 AE []testValueMarshaler
1656 AF []Proxy
1657 AG []testProxy
1658 }{
1659 A: []bool{true},
1660 B: []int32{123},
1661 C: []int64{456},
1662 D: []uint16{789},
1663 E: []uint64{101112},
1664 F: []float64{3.14159},
1665 G: []string{"Hello, world"},
1666 H: []map[string]string{{"foo": "bar"}},
1667 I: [][]byte{{0x01, 0x02, 0x03}},
1668 K: [1][2]string{{"baz", "qux"}},
1669 L: []struct {
1670 M string
1671 }{
1672 {
1673 M: "foobar",
1674 },
1675 },
1676 N: [][]string{{"foo", "bar"}},
1677 R: oids,
1678 T: nil,
1679 W: nil,
1680 X: []map[string]struct{}{},
1681 Y: []map[string]struct{}{{}},
1682 Z: []time.Time{now, now},
1683 AA: []json.Number{json.Number("5"), json.Number("10.1")},
1684 AB: []*url.URL{murl},
1685 AC: []primitive.Decimal128{decimal128},
1686 AD: []*time.Time{&now, &now},
1687 AE: []testValueMarshaler{
1688 {t: bsontype.String, buf: bsoncore.AppendString(nil, "hello")},
1689 {t: bsontype.String, buf: bsoncore.AppendString(nil, "world")},
1690 },
1691 AF: []Proxy{
1692 testProxy{ret: struct{ Hello string }{Hello: "world!"}},
1693 testProxy{ret: struct{ Foo string }{Foo: "bar"}},
1694 },
1695 AG: []testProxy{
1696 {ret: struct{ One int64 }{One: 1234567890}},
1697 {ret: struct{ Pi float64 }{Pi: 3.14159}},
1698 },
1699 },
1700 buildDocument(func(doc []byte) []byte {
1701 doc = appendArrayElement(doc, "a", bsoncore.AppendBooleanElement(nil, "0", true))
1702 doc = appendArrayElement(doc, "b", bsoncore.AppendInt32Element(nil, "0", 123))
1703 doc = appendArrayElement(doc, "c", bsoncore.AppendInt64Element(nil, "0", 456))
1704 doc = appendArrayElement(doc, "d", bsoncore.AppendInt32Element(nil, "0", 789))
1705 doc = appendArrayElement(doc, "e", bsoncore.AppendInt64Element(nil, "0", 101112))
1706 doc = appendArrayElement(doc, "f", bsoncore.AppendDoubleElement(nil, "0", 3.14159))
1707 doc = appendArrayElement(doc, "g", bsoncore.AppendStringElement(nil, "0", "Hello, world"))
1708 doc = appendArrayElement(doc, "h", bsoncore.BuildDocumentElement(nil, "0", bsoncore.AppendStringElement(nil, "foo", "bar")))
1709 doc = appendArrayElement(doc, "i", bsoncore.AppendBinaryElement(nil, "0", 0x00, []byte{0x01, 0x02, 0x03}))
1710 doc = appendArrayElement(doc, "k",
1711 appendArrayElement(nil, "0",
1712 bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "baz"), "1", "qux")),
1713 )
1714 doc = appendArrayElement(doc, "l", bsoncore.BuildDocumentElement(nil, "0", bsoncore.AppendStringElement(nil, "m", "foobar")))
1715 doc = appendArrayElement(doc, "n",
1716 appendArrayElement(nil, "0",
1717 bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "foo"), "1", "bar")),
1718 )
1719 doc = appendArrayElement(doc, "r",
1720 bsoncore.AppendObjectIDElement(
1721 bsoncore.AppendObjectIDElement(
1722 bsoncore.AppendObjectIDElement(nil,
1723 "0", oids[0]),
1724 "1", oids[1]),
1725 "2", oids[2]),
1726 )
1727 doc = bsoncore.AppendNullElement(doc, "t")
1728 doc = bsoncore.AppendNullElement(doc, "w")
1729 doc = appendArrayElement(doc, "x", nil)
1730 doc = appendArrayElement(doc, "y", bsoncore.BuildDocumentElement(nil, "0", nil))
1731 doc = appendArrayElement(doc, "z",
1732 bsoncore.AppendDateTimeElement(
1733 bsoncore.AppendDateTimeElement(
1734 nil, "0", now.UnixNano()/int64(time.Millisecond)),
1735 "1", now.UnixNano()/int64(time.Millisecond)),
1736 )
1737 doc = appendArrayElement(doc, "aa", bsoncore.AppendDoubleElement(bsoncore.AppendInt64Element(nil, "0", 5), "1", 10.10))
1738 doc = appendArrayElement(doc, "ab", bsoncore.AppendStringElement(nil, "0", murl.String()))
1739 doc = appendArrayElement(doc, "ac", bsoncore.AppendDecimal128Element(nil, "0", decimal128))
1740 doc = appendArrayElement(doc, "ad",
1741 bsoncore.AppendDateTimeElement(
1742 bsoncore.AppendDateTimeElement(nil, "0", now.UnixNano()/int64(time.Millisecond)),
1743 "1", now.UnixNano()/int64(time.Millisecond)),
1744 )
1745 doc = appendArrayElement(doc, "ae",
1746 bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "hello"), "1", "world"),
1747 )
1748 doc = appendArrayElement(doc, "af",
1749 bsoncore.AppendDocumentElement(
1750 bsoncore.AppendDocumentElement(nil, "0",
1751 bsoncore.BuildDocument(nil, bsoncore.AppendStringElement(nil, "hello", "world!")),
1752 ), "1",
1753 bsoncore.BuildDocument(nil, bsoncore.AppendStringElement(nil, "foo", "bar")),
1754 ),
1755 )
1756 doc = appendArrayElement(doc, "ag",
1757 bsoncore.AppendDocumentElement(
1758 bsoncore.AppendDocumentElement(nil, "0",
1759 bsoncore.BuildDocument(nil, bsoncore.AppendInt64Element(nil, "one", 1234567890)),
1760 ), "1",
1761 bsoncore.BuildDocument(nil, bsoncore.AppendDoubleElement(nil, "pi", 3.14159)),
1762 ),
1763 )
1764 return doc
1765 }(nil)),
1766 nil,
1767 },
1768 }
1769
1770 for _, tc := range testCases {
1771 t.Run(tc.name, func(t *testing.T) {
1772 b := make(bsonrw.SliceWriter, 0, 512)
1773 vw, err := bsonrw.NewBSONValueWriter(&b)
1774 noerr(t, err)
1775 reg := buildDefaultRegistry()
1776 enc, err := reg.LookupEncoder(reflect.TypeOf(tc.value))
1777 noerr(t, err)
1778 err = enc.EncodeValue(EncodeContext{Registry: reg}, vw, reflect.ValueOf(tc.value))
1779 if !errors.Is(err, tc.err) {
1780 t.Errorf("Did not receive expected error. got %v; want %v", err, tc.err)
1781 }
1782 if diff := cmp.Diff([]byte(b), tc.b); diff != "" {
1783 t.Errorf("Bytes written differ: (-got +want)\n%s", diff)
1784 t.Errorf("Bytes\ngot: %v\nwant:%v\n", b, tc.b)
1785 t.Errorf("Readers\ngot: %v\nwant:%v\n", bsoncore.Document(b), bsoncore.Document(tc.b))
1786 }
1787 })
1788 }
1789 })
1790
1791 t.Run("error path", func(t *testing.T) {
1792 testCases := []struct {
1793 name string
1794 value interface{}
1795 err error
1796 }{
1797 {
1798 "duplicate name struct",
1799 struct {
1800 A int64
1801 B int64 `bson:"a"`
1802 }{
1803 A: 0,
1804 B: 54321,
1805 },
1806 fmt.Errorf("duplicated key a"),
1807 },
1808 {
1809 "inline map",
1810 struct {
1811 Foo map[string]string `bson:",inline"`
1812 Baz string
1813 }{
1814 Foo: map[string]string{"baz": "bar"},
1815 Baz: "hi",
1816 },
1817 fmt.Errorf("Key baz of inlined map conflicts with a struct field name"),
1818 },
1819 }
1820
1821 for _, tc := range testCases {
1822 t.Run(tc.name, func(t *testing.T) {
1823 b := make(bsonrw.SliceWriter, 0, 512)
1824 vw, err := bsonrw.NewBSONValueWriter(&b)
1825 noerr(t, err)
1826 reg := buildDefaultRegistry()
1827 enc, err := reg.LookupEncoder(reflect.TypeOf(tc.value))
1828 noerr(t, err)
1829 err = enc.EncodeValue(EncodeContext{Registry: reg}, vw, reflect.ValueOf(tc.value))
1830 if err == nil || !strings.Contains(err.Error(), tc.err.Error()) {
1831 t.Errorf("Did not receive expected error. got %v; want %v", err, tc.err)
1832 }
1833 })
1834 }
1835 })
1836
1837 t.Run("EmptyInterfaceEncodeValue/nil", func(t *testing.T) {
1838 val := reflect.New(tEmpty).Elem()
1839 llvrw := new(bsonrwtest.ValueReaderWriter)
1840 err := dve.EmptyInterfaceEncodeValue(EncodeContext{Registry: NewRegistryBuilder().Build()}, llvrw, val)
1841 noerr(t, err)
1842 if llvrw.Invoked != bsonrwtest.WriteNull {
1843 t.Errorf("Incorrect method called. got %v; want %v", llvrw.Invoked, bsonrwtest.WriteNull)
1844 }
1845 })
1846
1847 t.Run("EmptyInterfaceEncodeValue/LookupEncoder error", func(t *testing.T) {
1848 val := reflect.New(tEmpty).Elem()
1849 val.Set(reflect.ValueOf(int64(1234567890)))
1850 llvrw := new(bsonrwtest.ValueReaderWriter)
1851 got := dve.EmptyInterfaceEncodeValue(EncodeContext{Registry: NewRegistryBuilder().Build()}, llvrw, val)
1852 want := ErrNoEncoder{Type: tInt64}
1853 if !compareErrors(got, want) {
1854 t.Errorf("Did not receive expected error. got %v; want %v", got, want)
1855 }
1856 })
1857 }
1858
1859 type testValueMarshaler struct {
1860 t bsontype.Type
1861 buf []byte
1862 err error
1863 }
1864
1865 func (tvm testValueMarshaler) MarshalBSONValue() (bsontype.Type, []byte, error) {
1866 return tvm.t, tvm.buf, tvm.err
1867 }
1868
1869 type testValueMarshalPtr struct {
1870 t bsontype.Type
1871 buf []byte
1872 err error
1873 }
1874
1875 func (tvm *testValueMarshalPtr) MarshalBSONValue() (bsontype.Type, []byte, error) {
1876 return tvm.t, tvm.buf, tvm.err
1877 }
1878
1879 type testMarshaler struct {
1880 buf []byte
1881 err error
1882 }
1883
1884 func (tvm testMarshaler) MarshalBSON() ([]byte, error) {
1885 return tvm.buf, tvm.err
1886 }
1887
1888 type testMarshalPtr struct {
1889 buf []byte
1890 err error
1891 }
1892
1893 func (tvm *testMarshalPtr) MarshalBSON() ([]byte, error) {
1894 return tvm.buf, tvm.err
1895 }
1896
1897 type testProxy struct {
1898 ret interface{}
1899 err error
1900 }
1901
1902 func (tp testProxy) ProxyBSON() (interface{}, error) { return tp.ret, tp.err }
1903
1904 type testProxyPtr struct {
1905 ret interface{}
1906 err error
1907 }
1908
1909 func (tp *testProxyPtr) ProxyBSON() (interface{}, error) { return tp.ret, tp.err }
1910
View as plain text