1
2
3
4
5
6
7 package bson
8
9 import (
10 "bytes"
11 "errors"
12 "reflect"
13 "testing"
14
15 "go.mongodb.org/mongo-driver/bson/bsoncodec"
16 "go.mongodb.org/mongo-driver/bson/bsonrw"
17 "go.mongodb.org/mongo-driver/bson/bsonrw/bsonrwtest"
18 "go.mongodb.org/mongo-driver/bson/bsontype"
19 "go.mongodb.org/mongo-driver/internal/assert"
20 "go.mongodb.org/mongo-driver/internal/require"
21 "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
22 )
23
24 func TestBasicEncode(t *testing.T) {
25 for _, tc := range marshalingTestCases {
26 t.Run(tc.name, func(t *testing.T) {
27 got := make(bsonrw.SliceWriter, 0, 1024)
28 vw, err := bsonrw.NewBSONValueWriter(&got)
29 noerr(t, err)
30 reg := DefaultRegistry
31 encoder, err := reg.LookupEncoder(reflect.TypeOf(tc.val))
32 noerr(t, err)
33 err = encoder.EncodeValue(bsoncodec.EncodeContext{Registry: reg}, vw, reflect.ValueOf(tc.val))
34 noerr(t, err)
35
36 if !bytes.Equal(got, tc.want) {
37 t.Errorf("Bytes are not equal. got %v; want %v", got, tc.want)
38 t.Errorf("Bytes:\n%v\n%v", got, tc.want)
39 }
40 })
41 }
42 }
43
44 func TestEncoderEncode(t *testing.T) {
45 for _, tc := range marshalingTestCases {
46 t.Run(tc.name, func(t *testing.T) {
47 got := make(bsonrw.SliceWriter, 0, 1024)
48 vw, err := bsonrw.NewBSONValueWriter(&got)
49 noerr(t, err)
50 enc, err := NewEncoder(vw)
51 noerr(t, err)
52 err = enc.Encode(tc.val)
53 noerr(t, err)
54
55 if !bytes.Equal(got, tc.want) {
56 t.Errorf("Bytes are not equal. got %v; want %v", got, tc.want)
57 t.Errorf("Bytes:\n%v\n%v", got, tc.want)
58 }
59 })
60 }
61
62 t.Run("Marshaler", func(t *testing.T) {
63 testCases := []struct {
64 name string
65 buf []byte
66 err error
67 wanterr error
68 vw bsonrw.ValueWriter
69 }{
70 {
71 "error",
72 nil,
73 errors.New("Marshaler error"),
74 errors.New("Marshaler error"),
75 &bsonrwtest.ValueReaderWriter{},
76 },
77 {
78 "copy error",
79 []byte{0x05, 0x00, 0x00, 0x00, 0x00},
80 nil,
81 errors.New("copy error"),
82 &bsonrwtest.ValueReaderWriter{Err: errors.New("copy error"), ErrAfter: bsonrwtest.WriteDocument},
83 },
84 {
85 "success",
86 []byte{0x07, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00},
87 nil,
88 nil,
89 nil,
90 },
91 }
92
93 for _, tc := range testCases {
94 t.Run(tc.name, func(t *testing.T) {
95 marshaler := testMarshaler{buf: tc.buf, err: tc.err}
96
97 var vw bsonrw.ValueWriter
98 var err error
99 b := make(bsonrw.SliceWriter, 0, 100)
100 compareVW := false
101 if tc.vw != nil {
102 vw = tc.vw
103 } else {
104 compareVW = true
105 vw, err = bsonrw.NewBSONValueWriter(&b)
106 noerr(t, err)
107 }
108 enc, err := NewEncoder(vw)
109 noerr(t, err)
110 got := enc.Encode(marshaler)
111 want := tc.wanterr
112 if !compareErrors(got, want) {
113 t.Errorf("Did not receive expected error. got %v; want %v", got, want)
114 }
115 if compareVW {
116 buf := b
117 if !bytes.Equal(buf, tc.buf) {
118 t.Errorf("Copied bytes do not match. got %v; want %v", buf, tc.buf)
119 }
120 }
121 })
122 }
123 })
124 }
125
126 type testMarshaler struct {
127 buf []byte
128 err error
129 }
130
131 func (tm testMarshaler) MarshalBSON() ([]byte, error) { return tm.buf, tm.err }
132
133 func docToBytes(d interface{}) []byte {
134 b, err := Marshal(d)
135 if err != nil {
136 panic(err)
137 }
138 return b
139 }
140
141 type stringerTest struct{}
142
143 func (stringerTest) String() string {
144 return "test key"
145 }
146
147 func TestEncoderConfiguration(t *testing.T) {
148 type inlineDuplicateInner struct {
149 Duplicate string
150 }
151
152 type inlineDuplicateOuter struct {
153 Inline inlineDuplicateInner `bson:",inline"`
154 Duplicate string
155 }
156
157 type zeroStruct struct {
158 MyString string
159 }
160
161 testCases := []struct {
162 description string
163 configure func(*Encoder)
164 input interface{}
165 want []byte
166 wantErr error
167 }{
168
169
170 {
171 description: "ErrorOnInlineDuplicates",
172 configure: func(enc *Encoder) {
173 enc.ErrorOnInlineDuplicates()
174 },
175 input: inlineDuplicateOuter{
176 Inline: inlineDuplicateInner{Duplicate: "inner"},
177 Duplicate: "outer",
178 },
179 wantErr: errors.New("struct bson.inlineDuplicateOuter has duplicated key duplicate"),
180 },
181
182
183 {
184 description: "IntMinSize",
185 configure: func(enc *Encoder) {
186 enc.IntMinSize()
187 },
188 input: D{
189 {Key: "myInt", Value: int(1)},
190 {Key: "myInt64", Value: int64(1)},
191 {Key: "myUint", Value: uint(1)},
192 {Key: "myUint32", Value: uint32(1)},
193 {Key: "myUint64", Value: uint64(1)},
194 },
195 want: bsoncore.NewDocumentBuilder().
196 AppendInt32("myInt", 1).
197 AppendInt32("myInt64", 1).
198 AppendInt32("myUint", 1).
199 AppendInt32("myUint32", 1).
200 AppendInt32("myUint64", 1).
201 Build(),
202 },
203
204 {
205 description: "StringifyMapKeysWithFmt",
206 configure: func(enc *Encoder) {
207 enc.StringifyMapKeysWithFmt()
208 },
209 input: map[stringerTest]string{
210 {}: "test value",
211 },
212 want: bsoncore.NewDocumentBuilder().
213 AppendString("test key", "test value").
214 Build(),
215 },
216
217 {
218 description: "NilMapAsEmpty",
219 configure: func(enc *Encoder) {
220 enc.NilMapAsEmpty()
221 },
222 input: D{{Key: "myMap", Value: map[string]string(nil)}},
223 want: bsoncore.NewDocumentBuilder().
224 AppendDocument("myMap", bsoncore.NewDocumentBuilder().Build()).
225 Build(),
226 },
227
228 {
229 description: "NilSliceAsEmpty",
230 configure: func(enc *Encoder) {
231 enc.NilSliceAsEmpty()
232 },
233 input: D{{Key: "mySlice", Value: []string(nil)}},
234 want: bsoncore.NewDocumentBuilder().
235 AppendArray("mySlice", bsoncore.NewArrayBuilder().Build()).
236 Build(),
237 },
238
239 {
240 description: "NilByteSliceAsEmpty",
241 configure: func(enc *Encoder) {
242 enc.NilByteSliceAsEmpty()
243 },
244 input: D{{Key: "myBytes", Value: []byte(nil)}},
245 want: bsoncore.NewDocumentBuilder().
246 AppendBinary("myBytes", bsontype.BinaryGeneric, []byte{}).
247 Build(),
248 },
249
250
251 {
252 description: "OmitZeroStruct",
253 configure: func(enc *Encoder) {
254 enc.OmitZeroStruct()
255 },
256 input: struct {
257 Zero zeroStruct `bson:",omitempty"`
258 }{},
259 want: bsoncore.NewDocumentBuilder().Build(),
260 },
261
262
263 {
264 description: "UseJSONStructTags",
265 configure: func(enc *Encoder) {
266 enc.UseJSONStructTags()
267 },
268 input: struct {
269 StructFieldName string `json:"jsonFieldName"`
270 }{
271 StructFieldName: "test value",
272 },
273 want: bsoncore.NewDocumentBuilder().
274 AppendString("jsonFieldName", "test value").
275 Build(),
276 },
277 }
278
279 for _, tc := range testCases {
280 tc := tc
281
282 t.Run(tc.description, func(t *testing.T) {
283 t.Parallel()
284
285 got := new(bytes.Buffer)
286 vw, err := bsonrw.NewBSONValueWriter(got)
287 require.NoError(t, err, "bsonrw.NewBSONValueWriter error")
288 enc, err := NewEncoder(vw)
289 require.NoError(t, err, "NewEncoder error")
290
291 tc.configure(enc)
292
293 err = enc.Encode(tc.input)
294 if tc.wantErr != nil {
295 assert.Equal(t, tc.wantErr, err, "expected and actual errors do not match")
296 return
297 }
298 require.NoError(t, err, "Encode error")
299
300 assert.Equal(t, tc.want, got.Bytes(), "expected and actual encoded BSON do not match")
301
302
303
304
305 var wantDoc D
306 err = Unmarshal(tc.want, &wantDoc)
307 require.NoError(t, err, "Unmarshal error")
308 var gotDoc D
309 err = Unmarshal(got.Bytes(), &gotDoc)
310 require.NoError(t, err, "Unmarshal error")
311
312 assert.Equal(t, wantDoc, gotDoc, "expected and actual decoded documents do not match")
313 })
314 }
315 }
316
View as plain text