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	"net/url"
14	"reflect"
15	"testing"
16	"time"
17
18	"github.com/google/go-cmp/cmp"
19	"go.mongodb.org/mongo-driver/bson/bsonrw"
20	"go.mongodb.org/mongo-driver/bson/bsonrw/bsonrwtest"
21	"go.mongodb.org/mongo-driver/bson/bsontype"
22	"go.mongodb.org/mongo-driver/bson/primitive"
23	"go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
24	"math"
25)
26
27func TestDefaultValueEncoders(t *testing.T) {
28	var dve DefaultValueEncoders
29	var wrong = func(string, string) string { return "wrong" }
30
31	type mybool bool
32	type myint8 int8
33	type myint16 int16
34	type myint32 int32
35	type myint64 int64
36	type myint int
37	type myuint8 uint8
38	type myuint16 uint16
39	type myuint32 uint32
40	type myuint64 uint64
41	type myuint uint
42	type myfloat32 float32
43	type myfloat64 float64
44	type mystring string
45
46	now := time.Now().Truncate(time.Millisecond)
47	pjsnum := new(json.Number)
48	*pjsnum = json.Number("3.14159")
49	d128 := primitive.NewDecimal128(12345, 67890)
50
51	type subtest struct {
52		name   string
53		val    interface{}
54		ectx   *EncodeContext
55		llvrw  *bsonrwtest.ValueReaderWriter
56		invoke bsonrwtest.Invoked
57		err    error
58	}
59
60	testCases := []struct {
61		name     string
62		ve       ValueEncoder
63		subtests []subtest
64	}{
65		{
66			"BooleanEncodeValue",
67			ValueEncoderFunc(dve.BooleanEncodeValue),
68			[]subtest{
69				{
70					"wrong type",
71					wrong,
72					nil,
73					nil,
74					bsonrwtest.Nothing,
75					ValueEncoderError{Name: "BooleanEncodeValue", Kinds: []reflect.Kind{reflect.Bool}, Received: reflect.ValueOf(wrong)},
76				},
77				{"fast path", bool(true), nil, nil, bsonrwtest.WriteBoolean, nil},
78				{"reflection path", mybool(true), nil, nil, bsonrwtest.WriteBoolean, nil},
79			},
80		},
81		{
82			"IntEncodeValue",
83			ValueEncoderFunc(dve.IntEncodeValue),
84			[]subtest{
85				{
86					"wrong type",
87					wrong,
88					nil,
89					nil,
90					bsonrwtest.Nothing,
91					ValueEncoderError{
92						Name:     "IntEncodeValue",
93						Kinds:    []reflect.Kind{reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int},
94						Received: reflect.ValueOf(wrong),
95					},
96				},
97				{"int8/fast path", int8(127), nil, nil, bsonrwtest.WriteInt32, nil},
98				{"int16/fast path", int16(32767), nil, nil, bsonrwtest.WriteInt32, nil},
99				{"int32/fast path", int32(2147483647), nil, nil, bsonrwtest.WriteInt32, nil},
100				{"int64/fast path", int64(1234567890987), nil, nil, bsonrwtest.WriteInt64, nil},
101				{"int64/fast path - minsize", int64(math.MaxInt32), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
102				{"int64/fast path - minsize too large", int64(math.MaxInt32 + 1), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
103				{"int64/fast path - minsize too small", int64(math.MinInt32 - 1), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
104				{"int/fast path - positive int32", int(math.MaxInt32 - 1), nil, nil, bsonrwtest.WriteInt32, nil},
105				{"int/fast path - negative int32", int(math.MinInt32 + 1), nil, nil, bsonrwtest.WriteInt32, nil},
106				{"int/fast path - MaxInt32", int(math.MaxInt32), nil, nil, bsonrwtest.WriteInt32, nil},
107				{"int/fast path - MinInt32", int(math.MinInt32), nil, nil, bsonrwtest.WriteInt32, nil},
108				{"int/fast path - larger than MaxInt32", int(math.MaxInt32 + 1), nil, nil, bsonrwtest.WriteInt64, nil},
109				{"int/fast path - smaller than MinInt32", int(math.MinInt32 - 1), nil, nil, bsonrwtest.WriteInt64, nil},
110				{"int8/reflection path", myint8(127), nil, nil, bsonrwtest.WriteInt32, nil},
111				{"int16/reflection path", myint16(32767), nil, nil, bsonrwtest.WriteInt32, nil},
112				{"int32/reflection path", myint32(2147483647), nil, nil, bsonrwtest.WriteInt32, nil},
113				{"int64/reflection path", myint64(1234567890987), nil, nil, bsonrwtest.WriteInt64, nil},
114				{"int64/reflection path - minsize", myint64(math.MaxInt32), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
115				{"int64/reflection path - minsize too large", myint64(math.MaxInt32 + 1), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
116				{"int64/reflection path - minsize too small", myint64(math.MinInt32 - 1), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
117				{"int/reflection path - positive int32", myint(math.MaxInt32 - 1), nil, nil, bsonrwtest.WriteInt32, nil},
118				{"int/reflection path - negative int32", myint(math.MinInt32 + 1), nil, nil, bsonrwtest.WriteInt32, nil},
119				{"int/reflection path - MaxInt32", myint(math.MaxInt32), nil, nil, bsonrwtest.WriteInt32, nil},
120				{"int/reflection path - MinInt32", myint(math.MinInt32), nil, nil, bsonrwtest.WriteInt32, nil},
121				{"int/reflection path - larger than MaxInt32", myint(math.MaxInt32 + 1), nil, nil, bsonrwtest.WriteInt64, nil},
122				{"int/reflection path - smaller than MinInt32", myint(math.MinInt32 - 1), nil, nil, bsonrwtest.WriteInt64, nil},
123			},
124		},
125		{
126			"UintEncodeValue",
127			ValueEncoderFunc(dve.UintEncodeValue),
128			[]subtest{
129				{
130					"wrong type",
131					wrong,
132					nil,
133					nil,
134					bsonrwtest.Nothing,
135					ValueEncoderError{
136						Name:     "UintEncodeValue",
137						Kinds:    []reflect.Kind{reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint},
138						Received: reflect.ValueOf(wrong),
139					},
140				},
141				{"uint8/fast path", uint8(127), nil, nil, bsonrwtest.WriteInt32, nil},
142				{"uint16/fast path", uint16(32767), nil, nil, bsonrwtest.WriteInt32, nil},
143				{"uint32/fast path", uint32(2147483647), nil, nil, bsonrwtest.WriteInt64, nil},
144				{"uint64/fast path", uint64(1234567890987), nil, nil, bsonrwtest.WriteInt64, nil},
145				{"uint/fast path", uint(1234567), nil, nil, bsonrwtest.WriteInt64, nil},
146				{"uint32/fast path - minsize", uint32(2147483647), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
147				{"uint64/fast path - minsize", uint64(2147483647), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
148				{"uint/fast path - minsize", uint(2147483647), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
149				{"uint32/fast path - minsize too large", uint32(2147483648), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
150				{"uint64/fast path - minsize too large", uint64(2147483648), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
151				{"uint/fast path - minsize too large", uint(2147483648), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
152				{"uint64/fast path - overflow", uint64(1 << 63), nil, nil, bsonrwtest.Nothing, fmt.Errorf("%d overflows int64", uint(1<<63))},
153				{"uint/fast path - overflow", uint(1 << 63), nil, nil, bsonrwtest.Nothing, fmt.Errorf("%d overflows int64", uint(1<<63))},
154				{"uint8/reflection path", myuint8(127), nil, nil, bsonrwtest.WriteInt32, nil},
155				{"uint16/reflection path", myuint16(32767), nil, nil, bsonrwtest.WriteInt32, nil},
156				{"uint32/reflection path", myuint32(2147483647), nil, nil, bsonrwtest.WriteInt64, nil},
157				{"uint64/reflection path", myuint64(1234567890987), nil, nil, bsonrwtest.WriteInt64, nil},
158				{"uint/reflection path", myuint(1234567890987), nil, nil, bsonrwtest.WriteInt64, nil},
159				{"uint32/reflection path - minsize", myuint32(2147483647), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
160				{"uint64/reflection path - minsize", myuint64(2147483647), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
161				{"uint/reflection path - minsize", myuint(2147483647), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt32, nil},
162				{"uint32/reflection path - minsize too large", myuint(1 << 31), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
163				{"uint64/reflection path - minsize too large", myuint64(1 << 31), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
164				{"uint/reflection path - minsize too large", myuint(2147483648), &EncodeContext{MinSize: true}, nil, bsonrwtest.WriteInt64, nil},
165				{"uint64/reflection path - overflow", myuint64(1 << 63), nil, nil, bsonrwtest.Nothing, fmt.Errorf("%d overflows int64", uint(1<<63))},
166				{"uint/reflection path - overflow", myuint(1 << 63), nil, nil, bsonrwtest.Nothing, fmt.Errorf("%d overflows int64", uint(1<<63))},
167			},
168		},
169		{
170			"FloatEncodeValue",
171			ValueEncoderFunc(dve.FloatEncodeValue),
172			[]subtest{
173				{
174					"wrong type",
175					wrong,
176					nil,
177					nil,
178					bsonrwtest.Nothing,
179					ValueEncoderError{
180						Name:     "FloatEncodeValue",
181						Kinds:    []reflect.Kind{reflect.Float32, reflect.Float64},
182						Received: reflect.ValueOf(wrong),
183					},
184				},
185				{"float32/fast path", float32(3.14159), nil, nil, bsonrwtest.WriteDouble, nil},
186				{"float64/fast path", float64(3.14159), nil, nil, bsonrwtest.WriteDouble, nil},
187				{"float32/reflection path", myfloat32(3.14159), nil, nil, bsonrwtest.WriteDouble, nil},
188				{"float64/reflection path", myfloat64(3.14159), nil, nil, bsonrwtest.WriteDouble, nil},
189			},
190		},
191		{
192			"TimeEncodeValue",
193			ValueEncoderFunc(dve.TimeEncodeValue),
194			[]subtest{
195				{
196					"wrong type",
197					wrong,
198					nil,
199					nil,
200					bsonrwtest.Nothing,
201					ValueEncoderError{Name: "TimeEncodeValue", Types: []reflect.Type{tTime}, Received: reflect.ValueOf(wrong)},
202				},
203				{"time.Time", now, nil, nil, bsonrwtest.WriteDateTime, nil},
204			},
205		},
206		{
207			"MapEncodeValue",
208			ValueEncoderFunc(dve.MapEncodeValue),
209			[]subtest{
210				{
211					"wrong kind",
212					wrong,
213					nil,
214					nil,
215					bsonrwtest.Nothing,
216					ValueEncoderError{Name: "MapEncodeValue", Kinds: []reflect.Kind{reflect.Map}, Received: reflect.ValueOf(wrong)},
217				},
218				{
219					"wrong kind (non-string key)",
220					map[int]interface{}{},
221					nil,
222					nil,
223					bsonrwtest.Nothing,
224					ValueEncoderError{
225						Name:     "MapEncodeValue",
226						Kinds:    []reflect.Kind{reflect.Map},
227						Received: reflect.ValueOf(map[int]interface{}{}),
228					},
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]interface{}{},
241					&EncodeContext{Registry: NewRegistryBuilder().Build()},
242					&bsonrwtest.ValueReaderWriter{},
243					bsonrwtest.WriteDocument,
244					ErrNoEncoder{Type: reflect.TypeOf((*interface{})(nil)).Elem()},
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		},
264		{
265			"ArrayEncodeValue",
266			ValueEncoderFunc(dve.ArrayEncodeValue),
267			[]subtest{
268				{
269					"wrong kind",
270					wrong,
271					nil,
272					nil,
273					bsonrwtest.Nothing,
274					ValueEncoderError{Name: "ArrayEncodeValue", Kinds: []reflect.Kind{reflect.Array}, Received: reflect.ValueOf(wrong)},
275				},
276				{
277					"WriteArray Error",
278					[1]string{},
279					nil,
280					&bsonrwtest.ValueReaderWriter{Err: errors.New("wa error"), ErrAfter: bsonrwtest.WriteArray},
281					bsonrwtest.WriteArray,
282					errors.New("wa error"),
283				},
284				{
285					"Lookup Error",
286					[1]interface{}{},
287					&EncodeContext{Registry: NewRegistryBuilder().Build()},
288					&bsonrwtest.ValueReaderWriter{},
289					bsonrwtest.WriteArray,
290					ErrNoEncoder{Type: reflect.TypeOf((*interface{})(nil)).Elem()},
291				},
292				{
293					"WriteArrayElement Error",
294					[1]string{"foo"},
295					&EncodeContext{Registry: buildDefaultRegistry()},
296					&bsonrwtest.ValueReaderWriter{Err: errors.New("wae error"), ErrAfter: bsonrwtest.WriteArrayElement},
297					bsonrwtest.WriteArrayElement,
298					errors.New("wae error"),
299				},
300				{
301					"EncodeValue Error",
302					[1]string{"foo"},
303					&EncodeContext{Registry: buildDefaultRegistry()},
304					&bsonrwtest.ValueReaderWriter{Err: errors.New("ev error"), ErrAfter: bsonrwtest.WriteString},
305					bsonrwtest.WriteString,
306					errors.New("ev error"),
307				},
308				{
309					"[1]primitive.E/success",
310					[1]primitive.E{{"hello", "world"}},
311					&EncodeContext{Registry: buildDefaultRegistry()},
312					nil,
313					bsonrwtest.WriteDocumentEnd,
314					nil,
315				},
316				{
317					"[1]primitive.E/success",
318					[1]primitive.E{{"hello", nil}},
319					&EncodeContext{Registry: buildDefaultRegistry()},
320					nil,
321					bsonrwtest.WriteDocumentEnd,
322					nil,
323				},
324			},
325		},
326		{
327			"SliceEncodeValue",
328			ValueEncoderFunc(dve.SliceEncodeValue),
329			[]subtest{
330				{
331					"wrong kind",
332					wrong,
333					nil,
334					nil,
335					bsonrwtest.Nothing,
336					ValueEncoderError{Name: "SliceEncodeValue", Kinds: []reflect.Kind{reflect.Slice}, Received: reflect.ValueOf(wrong)},
337				},
338				{
339					"WriteArray Error",
340					[]string{},
341					nil,
342					&bsonrwtest.ValueReaderWriter{Err: errors.New("wa error"), ErrAfter: bsonrwtest.WriteArray},
343					bsonrwtest.WriteArray,
344					errors.New("wa error"),
345				},
346				{
347					"Lookup Error",
348					[]interface{}{},
349					&EncodeContext{Registry: NewRegistryBuilder().Build()},
350					&bsonrwtest.ValueReaderWriter{},
351					bsonrwtest.WriteArray,
352					ErrNoEncoder{Type: reflect.TypeOf((*interface{})(nil)).Elem()},
353				},
354				{
355					"WriteArrayElement Error",
356					[]string{"foo"},
357					&EncodeContext{Registry: buildDefaultRegistry()},
358					&bsonrwtest.ValueReaderWriter{Err: errors.New("wae error"), ErrAfter: bsonrwtest.WriteArrayElement},
359					bsonrwtest.WriteArrayElement,
360					errors.New("wae error"),
361				},
362				{
363					"EncodeValue Error",
364					[]string{"foo"},
365					&EncodeContext{Registry: buildDefaultRegistry()},
366					&bsonrwtest.ValueReaderWriter{Err: errors.New("ev error"), ErrAfter: bsonrwtest.WriteString},
367					bsonrwtest.WriteString,
368					errors.New("ev error"),
369				},
370				{
371					"D/success",
372					primitive.D{{"hello", "world"}},
373					&EncodeContext{Registry: buildDefaultRegistry()},
374					nil,
375					bsonrwtest.WriteDocumentEnd,
376					nil,
377				},
378				{
379					"D/success",
380					primitive.D{{"hello", nil}},
381					&EncodeContext{Registry: buildDefaultRegistry()},
382					nil,
383					bsonrwtest.WriteDocumentEnd,
384					nil,
385				},
386			},
387		},
388		{
389			"ObjectIDEncodeValue",
390			ValueEncoderFunc(dve.ObjectIDEncodeValue),
391			[]subtest{
392				{
393					"wrong type",
394					wrong,
395					nil,
396					nil,
397					bsonrwtest.Nothing,
398					ValueEncoderError{Name: "ObjectIDEncodeValue", Types: []reflect.Type{tOID}, Received: reflect.ValueOf(wrong)},
399				},
400				{
401					"primitive.ObjectID/success",
402					primitive.ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
403					nil, nil, bsonrwtest.WriteObjectID, nil,
404				},
405			},
406		},
407		{
408			"Decimal128EncodeValue",
409			ValueEncoderFunc(dve.Decimal128EncodeValue),
410			[]subtest{
411				{
412					"wrong type",
413					wrong,
414					nil,
415					nil,
416					bsonrwtest.Nothing,
417					ValueEncoderError{Name: "Decimal128EncodeValue", Types: []reflect.Type{tDecimal}, Received: reflect.ValueOf(wrong)},
418				},
419				{"Decimal128/success", d128, nil, nil, bsonrwtest.WriteDecimal128, nil},
420			},
421		},
422		{
423			"JSONNumberEncodeValue",
424			ValueEncoderFunc(dve.JSONNumberEncodeValue),
425			[]subtest{
426				{
427					"wrong type",
428					wrong,
429					nil,
430					nil,
431					bsonrwtest.Nothing,
432					ValueEncoderError{Name: "JSONNumberEncodeValue", Types: []reflect.Type{tJSONNumber}, Received: reflect.ValueOf(wrong)},
433				},
434				{
435					"json.Number/invalid",
436					json.Number("hello world"),
437					nil, nil, bsonrwtest.Nothing, errors.New(`strconv.ParseFloat: parsing "hello world": invalid syntax`),
438				},
439				{
440					"json.Number/int64/success",
441					json.Number("1234567890"),
442					nil, nil, bsonrwtest.WriteInt64, nil,
443				},
444				{
445					"json.Number/float64/success",
446					json.Number("3.14159"),
447					nil, nil, bsonrwtest.WriteDouble, nil,
448				},
449			},
450		},
451		{
452			"URLEncodeValue",
453			ValueEncoderFunc(dve.URLEncodeValue),
454			[]subtest{
455				{
456					"wrong type",
457					wrong,
458					nil,
459					nil,
460					bsonrwtest.Nothing,
461					ValueEncoderError{Name: "URLEncodeValue", Types: []reflect.Type{tURL}, Received: reflect.ValueOf(wrong)},
462				},
463				{"url.URL", url.URL{Scheme: "http", Host: "example.com"}, nil, nil, bsonrwtest.WriteString, nil},
464			},
465		},
466		{
467			"ByteSliceEncodeValue",
468			ValueEncoderFunc(dve.ByteSliceEncodeValue),
469			[]subtest{
470				{
471					"wrong type",
472					wrong,
473					nil,
474					nil,
475					bsonrwtest.Nothing,
476					ValueEncoderError{Name: "ByteSliceEncodeValue", Types: []reflect.Type{tByteSlice}, Received: reflect.ValueOf(wrong)},
477				},
478				{"[]byte", []byte{0x01, 0x02, 0x03}, nil, nil, bsonrwtest.WriteBinary, nil},
479				{"[]byte/nil", []byte(nil), nil, nil, bsonrwtest.WriteNull, nil},
480			},
481		},
482		{
483			"EmptyInterfaceEncodeValue",
484			ValueEncoderFunc(dve.EmptyInterfaceEncodeValue),
485			[]subtest{
486				{
487					"wrong type",
488					wrong,
489					nil,
490					nil,
491					bsonrwtest.Nothing,
492					ValueEncoderError{Name: "EmptyInterfaceEncodeValue", Types: []reflect.Type{tEmpty}, Received: reflect.ValueOf(wrong)},
493				},
494			},
495		},
496		{
497			"ValueMarshalerEncodeValue",
498			ValueEncoderFunc(dve.ValueMarshalerEncodeValue),
499			[]subtest{
500				{
501					"wrong type",
502					wrong,
503					nil,
504					nil,
505					bsonrwtest.Nothing,
506					ValueEncoderError{
507						Name:     "ValueMarshalerEncodeValue",
508						Types:    []reflect.Type{tValueMarshaler},
509						Received: reflect.ValueOf(wrong),
510					},
511				},
512				{
513					"MarshalBSONValue error",
514					testValueMarshaler{err: errors.New("mbsonv error")},
515					nil,
516					nil,
517					bsonrwtest.Nothing,
518					errors.New("mbsonv error"),
519				},
520				{
521					"Copy error",
522					testValueMarshaler{},
523					nil,
524					nil,
525					bsonrwtest.Nothing,
526					fmt.Errorf("Cannot copy unknown BSON type %s", bsontype.Type(0)),
527				},
528				{
529					"success",
530					testValueMarshaler{t: bsontype.String, buf: []byte{0x04, 0x00, 0x00, 0x00, 'f', 'o', 'o', 0x00}},
531					nil,
532					nil,
533					bsonrwtest.WriteString,
534					nil,
535				},
536			},
537		},
538		{
539			"MarshalerEncodeValue",
540			ValueEncoderFunc(dve.MarshalerEncodeValue),
541			[]subtest{
542				{
543					"wrong type",
544					wrong,
545					nil,
546					nil,
547					bsonrwtest.Nothing,
548					ValueEncoderError{Name: "MarshalerEncodeValue", Types: []reflect.Type{tMarshaler}, Received: reflect.ValueOf(wrong)},
549				},
550				{
551					"MarshalBSON error",
552					testMarshaler{err: errors.New("mbson error")},
553					nil,
554					nil,
555					bsonrwtest.Nothing,
556					errors.New("mbson error"),
557				},
558				{
559					"success",
560					testMarshaler{buf: bsoncore.BuildDocument(nil, bsoncore.AppendDoubleElement(nil, "pi", 3.14159))},
561					nil,
562					nil,
563					bsonrwtest.WriteDocumentEnd,
564					nil,
565				},
566			},
567		},
568		{
569			"ProxyEncodeValue",
570			ValueEncoderFunc(dve.ProxyEncodeValue),
571			[]subtest{
572				{
573					"wrong type",
574					wrong,
575					nil,
576					nil,
577					bsonrwtest.Nothing,
578					ValueEncoderError{Name: "ProxyEncodeValue", Types: []reflect.Type{tProxy}, Received: reflect.ValueOf(wrong)},
579				},
580				{
581					"Proxy error",
582					testProxy{err: errors.New("proxy error")},
583					nil,
584					nil,
585					bsonrwtest.Nothing,
586					errors.New("proxy error"),
587				},
588				{
589					"Lookup error",
590					testProxy{ret: nil},
591					&EncodeContext{Registry: buildDefaultRegistry()},
592					nil,
593					bsonrwtest.Nothing,
594					ErrNoEncoder{Type: nil},
595				},
596				{
597					"success",
598					testProxy{ret: int64(1234567890)},
599					&EncodeContext{Registry: buildDefaultRegistry()},
600					nil,
601					bsonrwtest.WriteInt64,
602					nil,
603				},
604			},
605		},
606		{
607			"PointerCodec.EncodeValue",
608			NewPointerCodec(),
609			[]subtest{
610				{
611					"nil",
612					nil,
613					nil,
614					nil,
615					bsonrwtest.WriteNull,
616					nil,
617				},
618				{
619					"not pointer",
620					int32(123456),
621					nil,
622					nil,
623					bsonrwtest.Nothing,
624					ValueEncoderError{Name: "PointerCodec.EncodeValue", Kinds: []reflect.Kind{reflect.Ptr}, Received: reflect.ValueOf(int32(123456))},
625				},
626				{
627					"typed nil",
628					(*int32)(nil),
629					nil,
630					nil,
631					bsonrwtest.WriteNull,
632					nil,
633				},
634				{
635					"no encoder",
636					&wrong,
637					&EncodeContext{Registry: buildDefaultRegistry()},
638					nil,
639					bsonrwtest.Nothing,
640					ErrNoEncoder{Type: reflect.TypeOf(wrong)},
641				},
642			},
643		},
644		{
645			"JavaScriptEncodeValue",
646			ValueEncoderFunc(dve.JavaScriptEncodeValue),
647			[]subtest{
648				{
649					"wrong type",
650					wrong,
651					nil,
652					nil,
653					bsonrwtest.Nothing,
654					ValueEncoderError{Name: "JavaScriptEncodeValue", Types: []reflect.Type{tJavaScript}, Received: reflect.ValueOf(wrong)},
655				},
656				{"JavaScript", primitive.JavaScript("foobar"), nil, nil, bsonrwtest.WriteJavascript, nil},
657			},
658		},
659		{
660			"SymbolEncodeValue",
661			ValueEncoderFunc(dve.SymbolEncodeValue),
662			[]subtest{
663				{
664					"wrong type",
665					wrong,
666					nil,
667					nil,
668					bsonrwtest.Nothing,
669					ValueEncoderError{Name: "SymbolEncodeValue", Types: []reflect.Type{tSymbol}, Received: reflect.ValueOf(wrong)},
670				},
671				{"Symbol", primitive.Symbol("foobar"), nil, nil, bsonrwtest.WriteSymbol, nil},
672			},
673		},
674		{
675			"BinaryEncodeValue",
676			ValueEncoderFunc(dve.BinaryEncodeValue),
677			[]subtest{
678				{
679					"wrong type",
680					wrong,
681					nil,
682					nil,
683					bsonrwtest.Nothing,
684					ValueEncoderError{Name: "BinaryEncodeValue", Types: []reflect.Type{tBinary}, Received: reflect.ValueOf(wrong)},
685				},
686				{"Binary/success", primitive.Binary{Data: []byte{0x01, 0x02}, Subtype: 0xFF}, nil, nil, bsonrwtest.WriteBinaryWithSubtype, nil},
687			},
688		},
689		{
690			"UndefinedEncodeValue",
691			ValueEncoderFunc(dve.UndefinedEncodeValue),
692			[]subtest{
693				{
694					"wrong type",
695					wrong,
696					nil,
697					nil,
698					bsonrwtest.Nothing,
699					ValueEncoderError{Name: "UndefinedEncodeValue", Types: []reflect.Type{tUndefined}, Received: reflect.ValueOf(wrong)},
700				},
701				{"Undefined/success", primitive.Undefined{}, nil, nil, bsonrwtest.WriteUndefined, nil},
702			},
703		},
704		{
705			"DateTimeEncodeValue",
706			ValueEncoderFunc(dve.DateTimeEncodeValue),
707			[]subtest{
708				{
709					"wrong type",
710					wrong,
711					nil,
712					nil,
713					bsonrwtest.Nothing,
714					ValueEncoderError{Name: "DateTimeEncodeValue", Types: []reflect.Type{tDateTime}, Received: reflect.ValueOf(wrong)},
715				},
716				{"DateTime/success", primitive.DateTime(1234567890), nil, nil, bsonrwtest.WriteDateTime, nil},
717			},
718		},
719		{
720			"NullEncodeValue",
721			ValueEncoderFunc(dve.NullEncodeValue),
722			[]subtest{
723				{
724					"wrong type",
725					wrong,
726					nil,
727					nil,
728					bsonrwtest.Nothing,
729					ValueEncoderError{Name: "NullEncodeValue", Types: []reflect.Type{tNull}, Received: reflect.ValueOf(wrong)},
730				},
731				{"Null/success", primitive.Null{}, nil, nil, bsonrwtest.WriteNull, nil},
732			},
733		},
734		{
735			"RegexEncodeValue",
736			ValueEncoderFunc(dve.RegexEncodeValue),
737			[]subtest{
738				{
739					"wrong type",
740					wrong,
741					nil,
742					nil,
743					bsonrwtest.Nothing,
744					ValueEncoderError{Name: "RegexEncodeValue", Types: []reflect.Type{tRegex}, Received: reflect.ValueOf(wrong)},
745				},
746				{"Regex/success", primitive.Regex{Pattern: "foo", Options: "bar"}, nil, nil, bsonrwtest.WriteRegex, nil},
747			},
748		},
749		{
750			"DBPointerEncodeValue",
751			ValueEncoderFunc(dve.DBPointerEncodeValue),
752			[]subtest{
753				{
754					"wrong type",
755					wrong,
756					nil,
757					nil,
758					bsonrwtest.Nothing,
759					ValueEncoderError{Name: "DBPointerEncodeValue", Types: []reflect.Type{tDBPointer}, Received: reflect.ValueOf(wrong)},
760				},
761				{
762					"DBPointer/success",
763					primitive.DBPointer{
764						DB:      "foobar",
765						Pointer: primitive.ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C},
766					},
767					nil, nil, bsonrwtest.WriteDBPointer, nil,
768				},
769			},
770		},
771		{
772			"TimestampEncodeValue",
773			ValueEncoderFunc(dve.TimestampEncodeValue),
774			[]subtest{
775				{
776					"wrong type",
777					wrong,
778					nil,
779					nil,
780					bsonrwtest.Nothing,
781					ValueEncoderError{Name: "TimestampEncodeValue", Types: []reflect.Type{tTimestamp}, Received: reflect.ValueOf(wrong)},
782				},
783				{"Timestamp/success", primitive.Timestamp{T: 12345, I: 67890}, nil, nil, bsonrwtest.WriteTimestamp, nil},
784			},
785		},
786		{
787			"MinKeyEncodeValue",
788			ValueEncoderFunc(dve.MinKeyEncodeValue),
789			[]subtest{
790				{
791					"wrong type",
792					wrong,
793					nil,
794					nil,
795					bsonrwtest.Nothing,
796					ValueEncoderError{Name: "MinKeyEncodeValue", Types: []reflect.Type{tMinKey}, Received: reflect.ValueOf(wrong)},
797				},
798				{"MinKey/success", primitive.MinKey{}, nil, nil, bsonrwtest.WriteMinKey, nil},
799			},
800		},
801		{
802			"MaxKeyEncodeValue",
803			ValueEncoderFunc(dve.MaxKeyEncodeValue),
804			[]subtest{
805				{
806					"wrong type",
807					wrong,
808					nil,
809					nil,
810					bsonrwtest.Nothing,
811					ValueEncoderError{Name: "MaxKeyEncodeValue", Types: []reflect.Type{tMaxKey}, Received: reflect.ValueOf(wrong)},
812				},
813				{"MaxKey/success", primitive.MaxKey{}, nil, nil, bsonrwtest.WriteMaxKey, nil},
814			},
815		},
816		{
817			"CoreDocumentEncodeValue",
818			ValueEncoderFunc(dve.CoreDocumentEncodeValue),
819			[]subtest{
820				{
821					"wrong type",
822					wrong,
823					nil,
824					nil,
825					bsonrwtest.Nothing,
826					ValueEncoderError{
827						Name:     "CoreDocumentEncodeValue",
828						Types:    []reflect.Type{tCoreDocument},
829						Received: reflect.ValueOf(wrong),
830					},
831				},
832				{
833					"WriteDocument Error",
834					bsoncore.Document{},
835					nil,
836					&bsonrwtest.ValueReaderWriter{Err: errors.New("wd error"), ErrAfter: bsonrwtest.WriteDocument},
837					bsonrwtest.WriteDocument,
838					errors.New("wd error"),
839				},
840				{
841					"bsoncore.Document.Elements Error",
842					bsoncore.Document{0xFF, 0x00, 0x00, 0x00, 0x00},
843					nil,
844					&bsonrwtest.ValueReaderWriter{},
845					bsonrwtest.WriteDocument,
846					errors.New("length read exceeds number of bytes available. length=5 bytes=255"),
847				},
848				{
849					"WriteDocumentElement Error",
850					bsoncore.Document(buildDocument(bsoncore.AppendNullElement(nil, "foo"))),
851					nil,
852					&bsonrwtest.ValueReaderWriter{Err: errors.New("wde error"), ErrAfter: bsonrwtest.WriteDocumentElement},
853					bsonrwtest.WriteDocumentElement,
854					errors.New("wde error"),
855				},
856				{
857					"encodeValue error",
858					bsoncore.Document(buildDocument(bsoncore.AppendNullElement(nil, "foo"))),
859					nil,
860					&bsonrwtest.ValueReaderWriter{Err: errors.New("ev error"), ErrAfter: bsonrwtest.WriteNull},
861					bsonrwtest.WriteNull,
862					errors.New("ev error"),
863				},
864				{
865					"iterator error",
866					bsoncore.Document{0x0C, 0x00, 0x00, 0x00, 0x01, 'f', 'o', 'o', 0x00, 0x01, 0x02, 0x03},
867					nil,
868					&bsonrwtest.ValueReaderWriter{},
869					bsonrwtest.WriteDocumentElement,
870					errors.New("not enough bytes available to read type. bytes=3 type=double"),
871				},
872			},
873		},
874		{
875			"CodeWithScopeEncodeValue",
876			ValueEncoderFunc(dve.CodeWithScopeEncodeValue),
877			[]subtest{
878				{
879					"wrong type",
880					wrong,
881					nil,
882					nil,
883					bsonrwtest.Nothing,
884					ValueEncoderError{
885						Name:     "CodeWithScopeEncodeValue",
886						Types:    []reflect.Type{tCodeWithScope},
887						Received: reflect.ValueOf(wrong),
888					},
889				},
890				{
891					"WriteCodeWithScope error",
892					primitive.CodeWithScope{},
893					nil,
894					&bsonrwtest.ValueReaderWriter{Err: errors.New("wcws error"), ErrAfter: bsonrwtest.WriteCodeWithScope},
895					bsonrwtest.WriteCodeWithScope,
896					errors.New("wcws error"),
897				},
898				{
899					"CodeWithScope/success",
900					primitive.CodeWithScope{
901						Code:  "var hello = 'world';",
902						Scope: primitive.D{},
903					},
904					&EncodeContext{Registry: buildDefaultRegistry()},
905					nil, bsonrwtest.WriteDocumentEnd, nil,
906				},
907			},
908		},
909	}
910
911	for _, tc := range testCases {
912		t.Run(tc.name, func(t *testing.T) {
913			for _, subtest := range tc.subtests {
914				t.Run(subtest.name, func(t *testing.T) {
915					var ec EncodeContext
916					if subtest.ectx != nil {
917						ec = *subtest.ectx
918					}
919					llvrw := new(bsonrwtest.ValueReaderWriter)
920					if subtest.llvrw != nil {
921						llvrw = subtest.llvrw
922					}
923					llvrw.T = t
924					err := tc.ve.EncodeValue(ec, llvrw, reflect.ValueOf(subtest.val))
925					if !compareErrors(err, subtest.err) {
926						t.Errorf("Errors do not match. got %v; want %v", err, subtest.err)
927					}
928					invoked := llvrw.Invoked
929					if !cmp.Equal(invoked, subtest.invoke) {
930						t.Errorf("Incorrect method invoked. got %v; want %v", invoked, subtest.invoke)
931					}
932				})
933			}
934		})
935	}
936
937	t.Run("success path", func(t *testing.T) {
938		oid := primitive.NewObjectID()
939		oids := []primitive.ObjectID{primitive.NewObjectID(), primitive.NewObjectID(), primitive.NewObjectID()}
940		var str = new(string)
941		*str = "bar"
942		now := time.Now().Truncate(time.Millisecond)
943		murl, err := url.Parse("https://mongodb.com/random-url?hello=world")
944		if err != nil {
945			t.Errorf("Error parsing URL: %v", err)
946			t.FailNow()
947		}
948		decimal128, err := primitive.ParseDecimal128("1.5e10")
949		if err != nil {
950			t.Errorf("Error parsing decimal128: %v", err)
951			t.FailNow()
952		}
953
954		testCases := []struct {
955			name  string
956			value interface{}
957			b     []byte
958			err   error
959		}{
960			{
961				"map[string]int",
962				map[string]int32{"foo": 1},
963				[]byte{
964					0x0E, 0x00, 0x00, 0x00,
965					0x10, 'f', 'o', 'o', 0x00,
966					0x01, 0x00, 0x00, 0x00,
967					0x00,
968				},
969				nil,
970			},
971			{
972				"map[string]primitive.ObjectID",
973				map[string]primitive.ObjectID{"foo": oid},
974				buildDocument(bsoncore.AppendObjectIDElement(nil, "foo", oid)),
975				nil,
976			},
977			{
978				"map[string][]int32",
979				map[string][]int32{"Z": {1, 2, 3}},
980				buildDocumentArray(func(doc []byte) []byte {
981					doc = bsoncore.AppendInt32Element(doc, "0", 1)
982					doc = bsoncore.AppendInt32Element(doc, "1", 2)
983					return bsoncore.AppendInt32Element(doc, "2", 3)
984				}),
985				nil,
986			},
987			{
988				"map[string][]primitive.ObjectID",
989				map[string][]primitive.ObjectID{"Z": oids},
990				buildDocumentArray(func(doc []byte) []byte {
991					doc = bsoncore.AppendObjectIDElement(doc, "0", oids[0])
992					doc = bsoncore.AppendObjectIDElement(doc, "1", oids[1])
993					return bsoncore.AppendObjectIDElement(doc, "2", oids[2])
994				}),
995				nil,
996			},
997			{
998				"map[string][]json.Number(int64)",
999				map[string][]json.Number{"Z": {json.Number("5"), json.Number("10")}},
1000				buildDocumentArray(func(doc []byte) []byte {
1001					doc = bsoncore.AppendInt64Element(doc, "0", 5)
1002					return bsoncore.AppendInt64Element(doc, "1", 10)
1003				}),
1004				nil,
1005			},
1006			{
1007				"map[string][]json.Number(float64)",
1008				map[string][]json.Number{"Z": {json.Number("5"), json.Number("10.1")}},
1009				buildDocumentArray(func(doc []byte) []byte {
1010					doc = bsoncore.AppendInt64Element(doc, "0", 5)
1011					return bsoncore.AppendDoubleElement(doc, "1", 10.1)
1012				}),
1013				nil,
1014			},
1015			{
1016				"map[string][]*url.URL",
1017				map[string][]*url.URL{"Z": {murl}},
1018				buildDocumentArray(func(doc []byte) []byte {
1019					return bsoncore.AppendStringElement(doc, "0", murl.String())
1020				}),
1021				nil,
1022			},
1023			{
1024				"map[string][]primitive.Decimal128",
1025				map[string][]primitive.Decimal128{"Z": {decimal128}},
1026				buildDocumentArray(func(doc []byte) []byte {
1027					return bsoncore.AppendDecimal128Element(doc, "0", decimal128)
1028				}),
1029				nil,
1030			},
1031			{
1032				"-",
1033				struct {
1034					A string `bson:"-"`
1035				}{
1036					A: "",
1037				},
1038				[]byte{0x05, 0x00, 0x00, 0x00, 0x00},
1039				nil,
1040			},
1041			{
1042				"omitempty",
1043				struct {
1044					A string `bson:",omitempty"`
1045				}{
1046					A: "",
1047				},
1048				[]byte{0x05, 0x00, 0x00, 0x00, 0x00},
1049				nil,
1050			},
1051			{
1052				"omitempty, empty time",
1053				struct {
1054					A time.Time `bson:",omitempty"`
1055				}{
1056					A: time.Time{},
1057				},
1058				[]byte{0x05, 0x00, 0x00, 0x00, 0x00},
1059				nil,
1060			},
1061			{
1062				"no private fields",
1063				noPrivateFields{a: "should be empty"},
1064				[]byte{0x05, 0x00, 0x00, 0x00, 0x00},
1065				nil,
1066			},
1067			{
1068				"minsize",
1069				struct {
1070					A int64 `bson:",minsize"`
1071				}{
1072					A: 12345,
1073				},
1074				buildDocument(bsoncore.AppendInt32Element(nil, "a", 12345)),
1075				nil,
1076			},
1077			{
1078				"inline",
1079				struct {
1080					Foo struct {
1081						A int64 `bson:",minsize"`
1082					} `bson:",inline"`
1083				}{
1084					Foo: struct {
1085						A int64 `bson:",minsize"`
1086					}{
1087						A: 12345,
1088					},
1089				},
1090				buildDocument(bsoncore.AppendInt32Element(nil, "a", 12345)),
1091				nil,
1092			},
1093			{
1094				"inline map",
1095				struct {
1096					Foo map[string]string `bson:",inline"`
1097				}{
1098					Foo: map[string]string{"foo": "bar"},
1099				},
1100				buildDocument(bsoncore.AppendStringElement(nil, "foo", "bar")),
1101				nil,
1102			},
1103			{
1104				"alternate name bson:name",
1105				struct {
1106					A string `bson:"foo"`
1107				}{
1108					A: "bar",
1109				},
1110				buildDocument(bsoncore.AppendStringElement(nil, "foo", "bar")),
1111				nil,
1112			},
1113			{
1114				"alternate name",
1115				struct {
1116					A string `bson:"foo"`
1117				}{
1118					A: "bar",
1119				},
1120				buildDocument(bsoncore.AppendStringElement(nil, "foo", "bar")),
1121				nil,
1122			},
1123			{
1124				"inline, omitempty",
1125				struct {
1126					A   string
1127					Foo zeroTest `bson:"omitempty,inline"`
1128				}{
1129					A:   "bar",
1130					Foo: zeroTest{true},
1131				},
1132				buildDocument(bsoncore.AppendStringElement(nil, "a", "bar")),
1133				nil,
1134			},
1135			{
1136				"struct{}",
1137				struct {
1138					A bool
1139					B int32
1140					C int64
1141					D uint16
1142					E uint64
1143					F float64
1144					G string
1145					H map[string]string
1146					I []byte
1147					K [2]string
1148					L struct {
1149						M string
1150					}
1151					Q  primitive.ObjectID
1152					T  []struct{}
1153					Y  json.Number
1154					Z  time.Time
1155					AA json.Number
1156					AB *url.URL
1157					AC primitive.Decimal128
1158					AD *time.Time
1159					AE testValueMarshaler
1160					AF Proxy
1161					AG testProxy
1162					AH map[string]interface{}
1163					AI primitive.CodeWithScope
1164				}{
1165					A: true,
1166					B: 123,
1167					C: 456,
1168					D: 789,
1169					E: 101112,
1170					F: 3.14159,
1171					G: "Hello, world",
1172					H: map[string]string{"foo": "bar"},
1173					I: []byte{0x01, 0x02, 0x03},
1174					K: [2]string{"baz", "qux"},
1175					L: struct {
1176						M string
1177					}{
1178						M: "foobar",
1179					},
1180					Q:  oid,
1181					T:  nil,
1182					Y:  json.Number("5"),
1183					Z:  now,
1184					AA: json.Number("10.1"),
1185					AB: murl,
1186					AC: decimal128,
1187					AD: &now,
1188					AE: testValueMarshaler{t: bsontype.String, buf: bsoncore.AppendString(nil, "hello, world")},
1189					AF: testProxy{ret: struct{ Hello string }{Hello: "world!"}},
1190					AG: testProxy{ret: struct{ Pi float64 }{Pi: 3.14159}},
1191					AH: nil,
1192					AI: primitive.CodeWithScope{Code: "var hello = 'world';", Scope: primitive.D{{"pi", 3.14159}}},
1193				},
1194				buildDocument(func(doc []byte) []byte {
1195					doc = bsoncore.AppendBooleanElement(doc, "a", true)
1196					doc = bsoncore.AppendInt32Element(doc, "b", 123)
1197					doc = bsoncore.AppendInt64Element(doc, "c", 456)
1198					doc = bsoncore.AppendInt32Element(doc, "d", 789)
1199					doc = bsoncore.AppendInt64Element(doc, "e", 101112)
1200					doc = bsoncore.AppendDoubleElement(doc, "f", 3.14159)
1201					doc = bsoncore.AppendStringElement(doc, "g", "Hello, world")
1202					doc = bsoncore.AppendDocumentElement(doc, "h", buildDocument(bsoncore.AppendStringElement(nil, "foo", "bar")))
1203					doc = bsoncore.AppendBinaryElement(doc, "i", 0x00, []byte{0x01, 0x02, 0x03})
1204					doc = bsoncore.AppendArrayElement(doc, "k",
1205						buildArray(bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "baz"), "1", "qux")),
1206					)
1207					doc = bsoncore.AppendDocumentElement(doc, "l", buildDocument(bsoncore.AppendStringElement(nil, "m", "foobar")))
1208					doc = bsoncore.AppendObjectIDElement(doc, "q", oid)
1209					doc = bsoncore.AppendNullElement(doc, "t")
1210					doc = bsoncore.AppendInt64Element(doc, "y", 5)
1211					doc = bsoncore.AppendDateTimeElement(doc, "z", now.UnixNano()/int64(time.Millisecond))
1212					doc = bsoncore.AppendDoubleElement(doc, "aa", 10.1)
1213					doc = bsoncore.AppendStringElement(doc, "ab", murl.String())
1214					doc = bsoncore.AppendDecimal128Element(doc, "ac", decimal128)
1215					doc = bsoncore.AppendDateTimeElement(doc, "ad", now.UnixNano()/int64(time.Millisecond))
1216					doc = bsoncore.AppendStringElement(doc, "ae", "hello, world")
1217					doc = bsoncore.AppendDocumentElement(doc, "af", buildDocument(bsoncore.AppendStringElement(nil, "hello", "world!")))
1218					doc = bsoncore.AppendDocumentElement(doc, "ag", buildDocument(bsoncore.AppendDoubleElement(nil, "pi", 3.14159)))
1219					doc = bsoncore.AppendNullElement(doc, "ah")
1220					doc = bsoncore.AppendCodeWithScopeElement(doc, "ai",
1221						"var hello = 'world';", buildDocument(bsoncore.AppendDoubleElement(nil, "pi", 3.14159)),
1222					)
1223					return doc
1224				}(nil)),
1225				nil,
1226			},
1227			{
1228				"struct{[]interface{}}",
1229				struct {
1230					A []bool
1231					B []int32
1232					C []int64
1233					D []uint16
1234					E []uint64
1235					F []float64
1236					G []string
1237					H []map[string]string
1238					I [][]byte
1239					K [1][2]string
1240					L []struct {
1241						M string
1242					}
1243					N  [][]string
1244					R  []primitive.ObjectID
1245					T  []struct{}
1246					W  []map[string]struct{}
1247					X  []map[string]struct{}
1248					Y  []map[string]struct{}
1249					Z  []time.Time
1250					AA []json.Number
1251					AB []*url.URL
1252					AC []primitive.Decimal128
1253					AD []*time.Time
1254					AE []testValueMarshaler
1255					AF []Proxy
1256					AG []testProxy
1257				}{
1258					A: []bool{true},
1259					B: []int32{123},
1260					C: []int64{456},
1261					D: []uint16{789},
1262					E: []uint64{101112},
1263					F: []float64{3.14159},
1264					G: []string{"Hello, world"},
1265					H: []map[string]string{{"foo": "bar"}},
1266					I: [][]byte{{0x01, 0x02, 0x03}},
1267					K: [1][2]string{{"baz", "qux"}},
1268					L: []struct {
1269						M string
1270					}{
1271						{
1272							M: "foobar",
1273						},
1274					},
1275					N:  [][]string{{"foo", "bar"}},
1276					R:  oids,
1277					T:  nil,
1278					W:  nil,
1279					X:  []map[string]struct{}{},   // Should be empty BSON Array
1280					Y:  []map[string]struct{}{{}}, // Should be BSON array with one element, an empty BSON SubDocument
1281					Z:  []time.Time{now, now},
1282					AA: []json.Number{json.Number("5"), json.Number("10.1")},
1283					AB: []*url.URL{murl},
1284					AC: []primitive.Decimal128{decimal128},
1285					AD: []*time.Time{&now, &now},
1286					AE: []testValueMarshaler{
1287						{t: bsontype.String, buf: bsoncore.AppendString(nil, "hello")},
1288						{t: bsontype.String, buf: bsoncore.AppendString(nil, "world")},
1289					},
1290					AF: []Proxy{
1291						testProxy{ret: struct{ Hello string }{Hello: "world!"}},
1292						testProxy{ret: struct{ Foo string }{Foo: "bar"}},
1293					},
1294					AG: []testProxy{
1295						{ret: struct{ One int64 }{One: 1234567890}},
1296						{ret: struct{ Pi float64 }{Pi: 3.14159}},
1297					},
1298				},
1299				buildDocument(func(doc []byte) []byte {
1300					doc = appendArrayElement(doc, "a", bsoncore.AppendBooleanElement(nil, "0", true))
1301					doc = appendArrayElement(doc, "b", bsoncore.AppendInt32Element(nil, "0", 123))
1302					doc = appendArrayElement(doc, "c", bsoncore.AppendInt64Element(nil, "0", 456))
1303					doc = appendArrayElement(doc, "d", bsoncore.AppendInt32Element(nil, "0", 789))
1304					doc = appendArrayElement(doc, "e", bsoncore.AppendInt64Element(nil, "0", 101112))
1305					doc = appendArrayElement(doc, "f", bsoncore.AppendDoubleElement(nil, "0", 3.14159))
1306					doc = appendArrayElement(doc, "g", bsoncore.AppendStringElement(nil, "0", "Hello, world"))
1307					doc = appendArrayElement(doc, "h", buildDocumentElement("0", bsoncore.AppendStringElement(nil, "foo", "bar")))
1308					doc = appendArrayElement(doc, "i", bsoncore.AppendBinaryElement(nil, "0", 0x00, []byte{0x01, 0x02, 0x03}))
1309					doc = appendArrayElement(doc, "k",
1310						buildArrayElement("0",
1311							bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "baz"), "1", "qux")),
1312					)
1313					doc = appendArrayElement(doc, "l", buildDocumentElement("0", bsoncore.AppendStringElement(nil, "m", "foobar")))
1314					doc = appendArrayElement(doc, "n",
1315						buildArrayElement("0",
1316							bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "foo"), "1", "bar")),
1317					)
1318					doc = appendArrayElement(doc, "r",
1319						bsoncore.AppendObjectIDElement(
1320							bsoncore.AppendObjectIDElement(
1321								bsoncore.AppendObjectIDElement(nil,
1322									"0", oids[0]),
1323								"1", oids[1]),
1324							"2", oids[2]),
1325					)
1326					doc = bsoncore.AppendNullElement(doc, "t")
1327					doc = bsoncore.AppendNullElement(doc, "w")
1328					doc = appendArrayElement(doc, "x", nil)
1329					doc = appendArrayElement(doc, "y", buildDocumentElement("0", nil))
1330					doc = appendArrayElement(doc, "z",
1331						bsoncore.AppendDateTimeElement(
1332							bsoncore.AppendDateTimeElement(
1333								nil, "0", now.UnixNano()/int64(time.Millisecond)),
1334							"1", now.UnixNano()/int64(time.Millisecond)),
1335					)
1336					doc = appendArrayElement(doc, "aa", bsoncore.AppendDoubleElement(bsoncore.AppendInt64Element(nil, "0", 5), "1", 10.10))
1337					doc = appendArrayElement(doc, "ab", bsoncore.AppendStringElement(nil, "0", murl.String()))
1338					doc = appendArrayElement(doc, "ac", bsoncore.AppendDecimal128Element(nil, "0", decimal128))
1339					doc = appendArrayElement(doc, "ad",
1340						bsoncore.AppendDateTimeElement(
1341							bsoncore.AppendDateTimeElement(nil, "0", now.UnixNano()/int64(time.Millisecond)),
1342							"1", now.UnixNano()/int64(time.Millisecond)),
1343					)
1344					doc = appendArrayElement(doc, "ae",
1345						bsoncore.AppendStringElement(bsoncore.AppendStringElement(nil, "0", "hello"), "1", "world"),
1346					)
1347					doc = appendArrayElement(doc, "af",
1348						bsoncore.AppendDocumentElement(
1349							bsoncore.AppendDocumentElement(nil, "0",
1350								bsoncore.BuildDocument(nil, bsoncore.AppendStringElement(nil, "hello", "world!")),
1351							), "1",
1352							bsoncore.BuildDocument(nil, bsoncore.AppendStringElement(nil, "foo", "bar")),
1353						),
1354					)
1355					doc = appendArrayElement(doc, "ag",
1356						bsoncore.AppendDocumentElement(
1357							bsoncore.AppendDocumentElement(nil, "0",
1358								bsoncore.BuildDocument(nil, bsoncore.AppendInt64Element(nil, "one", 1234567890)),
1359							), "1",
1360							bsoncore.BuildDocument(nil, bsoncore.AppendDoubleElement(nil, "pi", 3.14159)),
1361						),
1362					)
1363					return doc
1364				}(nil)),
1365				nil,
1366			},
1367		}
1368
1369		for _, tc := range testCases {
1370			t.Run(tc.name, func(t *testing.T) {
1371				b := make(bsonrw.SliceWriter, 0, 512)
1372				vw, err := bsonrw.NewBSONValueWriter(&b)
1373				noerr(t, err)
1374				reg := buildDefaultRegistry()
1375				enc, err := reg.LookupEncoder(reflect.TypeOf(tc.value))
1376				noerr(t, err)
1377				err = enc.EncodeValue(EncodeContext{Registry: reg}, vw, reflect.ValueOf(tc.value))
1378				if err != tc.err {
1379					t.Errorf("Did not receive expected error. got %v; want %v", err, tc.err)
1380				}
1381				if diff := cmp.Diff([]byte(b), tc.b); diff != "" {
1382					t.Errorf("Bytes written differ: (-got +want)\n%s", diff)
1383					t.Errorf("Bytes\ngot: %v\nwant:%v\n", b, tc.b)
1384					t.Errorf("Readers\ngot: %v\nwant:%v\n", bsoncore.Document(b), bsoncore.Document(tc.b))
1385				}
1386			})
1387		}
1388	})
1389
1390	t.Run("EmptyInterfaceEncodeValue/nil", func(t *testing.T) {
1391		val := reflect.New(tEmpty).Elem()
1392		llvrw := new(bsonrwtest.ValueReaderWriter)
1393		err := dve.EmptyInterfaceEncodeValue(EncodeContext{Registry: NewRegistryBuilder().Build()}, llvrw, val)
1394		noerr(t, err)
1395		if llvrw.Invoked != bsonrwtest.WriteNull {
1396			t.Errorf("Incorrect method called. got %v; want %v", llvrw.Invoked, bsonrwtest.WriteNull)
1397		}
1398	})
1399
1400	t.Run("EmptyInterfaceEncodeValue/LookupEncoder error", func(t *testing.T) {
1401		val := reflect.New(tEmpty).Elem()
1402		val.Set(reflect.ValueOf(int64(1234567890)))
1403		llvrw := new(bsonrwtest.ValueReaderWriter)
1404		got := dve.EmptyInterfaceEncodeValue(EncodeContext{Registry: NewRegistryBuilder().Build()}, llvrw, val)
1405		want := ErrNoEncoder{Type: tInt64}
1406		if !compareErrors(got, want) {
1407			t.Errorf("Did not recieve expected error. got %v; want %v", got, want)
1408		}
1409	})
1410}
1411
1412type testValueMarshaler struct {
1413	t   bsontype.Type
1414	buf []byte
1415	err error
1416}
1417
1418func (tvm testValueMarshaler) MarshalBSONValue() (bsontype.Type, []byte, error) {
1419	return tvm.t, tvm.buf, tvm.err
1420}
1421
1422type testMarshaler struct {
1423	buf []byte
1424	err error
1425}
1426
1427func (tvm testMarshaler) MarshalBSON() ([]byte, error) {
1428	return tvm.buf, tvm.err
1429}
1430
1431type testProxy struct {
1432	ret interface{}
1433	err error
1434}
1435
1436func (tp testProxy) ProxyBSON() (interface{}, error) { return tp.ret, tp.err }
1437