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