1
2
3
4
5
6
7 package bsonrw
8
9 import (
10 "bytes"
11 "errors"
12 "fmt"
13 "io/ioutil"
14 "math"
15 "reflect"
16 "strings"
17 "testing"
18
19 "go.mongodb.org/mongo-driver/bson/bsontype"
20 "go.mongodb.org/mongo-driver/bson/primitive"
21 "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
22 )
23
24 func TestNewBSONValueWriter(t *testing.T) {
25 _, got := NewBSONValueWriter(nil)
26 want := errNilWriter
27 if !compareErrors(got, want) {
28 t.Errorf("Returned error did not match what was expected. got %v; want %v", got, want)
29 }
30
31 vw, got := NewBSONValueWriter(errWriter{})
32 want = nil
33 if !compareErrors(got, want) {
34 t.Errorf("Returned error did not match what was expected. got %v; want %v", got, want)
35 }
36 if vw == nil {
37 t.Errorf("Expected non-nil ValueWriter to be returned from NewBSONValueWriter")
38 }
39 }
40
41 func TestValueWriter(t *testing.T) {
42 header := []byte{0x00, 0x00, 0x00, 0x00}
43 oid := primitive.ObjectID{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C}
44 testCases := []struct {
45 name string
46 fn interface{}
47 params []interface{}
48 want []byte
49 }{
50 {
51 "WriteBinary",
52 (*valueWriter).WriteBinary,
53 []interface{}{[]byte{0x01, 0x02, 0x03}},
54 bsoncore.AppendBinaryElement(header, "foo", 0x00, []byte{0x01, 0x02, 0x03}),
55 },
56 {
57 "WriteBinaryWithSubtype (not 0x02)",
58 (*valueWriter).WriteBinaryWithSubtype,
59 []interface{}{[]byte{0x01, 0x02, 0x03}, byte(0xFF)},
60 bsoncore.AppendBinaryElement(header, "foo", 0xFF, []byte{0x01, 0x02, 0x03}),
61 },
62 {
63 "WriteBinaryWithSubtype (0x02)",
64 (*valueWriter).WriteBinaryWithSubtype,
65 []interface{}{[]byte{0x01, 0x02, 0x03}, byte(0x02)},
66 bsoncore.AppendBinaryElement(header, "foo", 0x02, []byte{0x01, 0x02, 0x03}),
67 },
68 {
69 "WriteBoolean",
70 (*valueWriter).WriteBoolean,
71 []interface{}{true},
72 bsoncore.AppendBooleanElement(header, "foo", true),
73 },
74 {
75 "WriteDBPointer",
76 (*valueWriter).WriteDBPointer,
77 []interface{}{"bar", oid},
78 bsoncore.AppendDBPointerElement(header, "foo", "bar", oid),
79 },
80 {
81 "WriteDateTime",
82 (*valueWriter).WriteDateTime,
83 []interface{}{int64(12345678)},
84 bsoncore.AppendDateTimeElement(header, "foo", 12345678),
85 },
86 {
87 "WriteDecimal128",
88 (*valueWriter).WriteDecimal128,
89 []interface{}{primitive.NewDecimal128(10, 20)},
90 bsoncore.AppendDecimal128Element(header, "foo", primitive.NewDecimal128(10, 20)),
91 },
92 {
93 "WriteDouble",
94 (*valueWriter).WriteDouble,
95 []interface{}{float64(3.14159)},
96 bsoncore.AppendDoubleElement(header, "foo", 3.14159),
97 },
98 {
99 "WriteInt32",
100 (*valueWriter).WriteInt32,
101 []interface{}{int32(123456)},
102 bsoncore.AppendInt32Element(header, "foo", 123456),
103 },
104 {
105 "WriteInt64",
106 (*valueWriter).WriteInt64,
107 []interface{}{int64(1234567890)},
108 bsoncore.AppendInt64Element(header, "foo", 1234567890),
109 },
110 {
111 "WriteJavascript",
112 (*valueWriter).WriteJavascript,
113 []interface{}{"var foo = 'bar';"},
114 bsoncore.AppendJavaScriptElement(header, "foo", "var foo = 'bar';"),
115 },
116 {
117 "WriteMaxKey",
118 (*valueWriter).WriteMaxKey,
119 []interface{}{},
120 bsoncore.AppendMaxKeyElement(header, "foo"),
121 },
122 {
123 "WriteMinKey",
124 (*valueWriter).WriteMinKey,
125 []interface{}{},
126 bsoncore.AppendMinKeyElement(header, "foo"),
127 },
128 {
129 "WriteNull",
130 (*valueWriter).WriteNull,
131 []interface{}{},
132 bsoncore.AppendNullElement(header, "foo"),
133 },
134 {
135 "WriteObjectID",
136 (*valueWriter).WriteObjectID,
137 []interface{}{oid},
138 bsoncore.AppendObjectIDElement(header, "foo", oid),
139 },
140 {
141 "WriteRegex",
142 (*valueWriter).WriteRegex,
143 []interface{}{"bar", "baz"},
144 bsoncore.AppendRegexElement(header, "foo", "bar", "abz"),
145 },
146 {
147 "WriteString",
148 (*valueWriter).WriteString,
149 []interface{}{"hello, world!"},
150 bsoncore.AppendStringElement(header, "foo", "hello, world!"),
151 },
152 {
153 "WriteSymbol",
154 (*valueWriter).WriteSymbol,
155 []interface{}{"symbollolz"},
156 bsoncore.AppendSymbolElement(header, "foo", "symbollolz"),
157 },
158 {
159 "WriteTimestamp",
160 (*valueWriter).WriteTimestamp,
161 []interface{}{uint32(10), uint32(20)},
162 bsoncore.AppendTimestampElement(header, "foo", 10, 20),
163 },
164 {
165 "WriteUndefined",
166 (*valueWriter).WriteUndefined,
167 []interface{}{},
168 bsoncore.AppendUndefinedElement(header, "foo"),
169 },
170 }
171
172 for _, tc := range testCases {
173 t.Run(tc.name, func(t *testing.T) {
174 fn := reflect.ValueOf(tc.fn)
175 if fn.Kind() != reflect.Func {
176 t.Fatalf("fn must be of kind Func but it is a %v", fn.Kind())
177 }
178 if fn.Type().NumIn() != len(tc.params)+1 || fn.Type().In(0) != reflect.TypeOf((*valueWriter)(nil)) {
179 t.Fatalf("fn must have at least one parameter and the first parameter must be a *valueWriter")
180 }
181 if fn.Type().NumOut() != 1 || fn.Type().Out(0) != reflect.TypeOf((*error)(nil)).Elem() {
182 t.Fatalf("fn must have one return value and it must be an error.")
183 }
184 params := make([]reflect.Value, 1, len(tc.params)+1)
185 vw := newValueWriter(ioutil.Discard)
186 params[0] = reflect.ValueOf(vw)
187 for _, param := range tc.params {
188 params = append(params, reflect.ValueOf(param))
189 }
190 _, err := vw.WriteDocument()
191 noerr(t, err)
192 _, err = vw.WriteDocumentElement("foo")
193 noerr(t, err)
194
195 results := fn.Call(params)
196 if !results[0].IsValid() {
197 err = results[0].Interface().(error)
198 } else {
199 err = nil
200 }
201 noerr(t, err)
202 got := vw.buf
203 want := tc.want
204 if !bytes.Equal(got, want) {
205 t.Errorf("Bytes are not equal.\n\tgot %v\n\twant %v", got, want)
206 }
207
208 t.Run("incorrect transition", func(t *testing.T) {
209 vw = newValueWriter(ioutil.Discard)
210 results := fn.Call(params)
211 got := results[0].Interface().(error)
212 fnName := tc.name
213 if strings.Contains(fnName, "WriteBinary") {
214 fnName = "WriteBinaryWithSubtype"
215 }
216 want := TransitionError{current: mTopLevel, name: fnName, modes: []mode{mElement, mValue},
217 action: "write"}
218 if !compareErrors(got, want) {
219 t.Errorf("Errors do not match. got %v; want %v", got, want)
220 }
221 })
222 })
223 }
224
225 t.Run("WriteArray", func(t *testing.T) {
226 vw := newValueWriter(ioutil.Discard)
227 vw.push(mArray)
228 want := TransitionError{current: mArray, destination: mArray, parent: mTopLevel,
229 name: "WriteArray", modes: []mode{mElement, mValue}, action: "write"}
230 _, got := vw.WriteArray()
231 if !compareErrors(got, want) {
232 t.Errorf("Did not get expected error. got %v; want %v", got, want)
233 }
234 })
235 t.Run("WriteCodeWithScope", func(t *testing.T) {
236 vw := newValueWriter(ioutil.Discard)
237 vw.push(mArray)
238 want := TransitionError{current: mArray, destination: mCodeWithScope, parent: mTopLevel,
239 name: "WriteCodeWithScope", modes: []mode{mElement, mValue}, action: "write"}
240 _, got := vw.WriteCodeWithScope("")
241 if !compareErrors(got, want) {
242 t.Errorf("Did not get expected error. got %v; want %v", got, want)
243 }
244 })
245 t.Run("WriteDocument", func(t *testing.T) {
246 vw := newValueWriter(ioutil.Discard)
247 vw.push(mArray)
248 want := TransitionError{current: mArray, destination: mDocument, parent: mTopLevel,
249 name: "WriteDocument", modes: []mode{mElement, mValue, mTopLevel}, action: "write"}
250 _, got := vw.WriteDocument()
251 if !compareErrors(got, want) {
252 t.Errorf("Did not get expected error. got %v; want %v", got, want)
253 }
254 })
255 t.Run("WriteDocumentElement", func(t *testing.T) {
256 vw := newValueWriter(ioutil.Discard)
257 vw.push(mElement)
258 want := TransitionError{current: mElement,
259 destination: mElement,
260 parent: mTopLevel,
261 name: "WriteDocumentElement",
262 modes: []mode{mTopLevel, mDocument},
263 action: "write"}
264 _, got := vw.WriteDocumentElement("")
265 if !compareErrors(got, want) {
266 t.Errorf("Did not get expected error. got %v; want %v", got, want)
267 }
268 })
269 t.Run("WriteDocumentEnd", func(t *testing.T) {
270 vw := newValueWriter(ioutil.Discard)
271 vw.push(mElement)
272 want := fmt.Errorf("incorrect mode to end document: %s", mElement)
273 got := vw.WriteDocumentEnd()
274 if !compareErrors(got, want) {
275 t.Errorf("Did not get expected error. got %v; want %v", got, want)
276 }
277 vw.pop()
278 vw.buf = append(vw.buf, make([]byte, 1023)...)
279 maxSize = 512
280 want = errMaxDocumentSizeExceeded{size: 1024}
281 got = vw.WriteDocumentEnd()
282 if !compareErrors(got, want) {
283 t.Errorf("Did not get expected error. got %v; want %v", got, want)
284 }
285 maxSize = math.MaxInt32
286 want = errors.New("what a nice fake error we have here")
287 vw.w = errWriter{err: want}
288 got = vw.WriteDocumentEnd()
289 if !compareErrors(got, want) {
290 t.Errorf("Did not get expected error. got %v; want %v", got, want)
291 }
292 })
293 t.Run("WriteArrayElement", func(t *testing.T) {
294 vw := newValueWriter(ioutil.Discard)
295 vw.push(mElement)
296 want := TransitionError{current: mElement,
297 destination: mValue,
298 parent: mTopLevel,
299 name: "WriteArrayElement",
300 modes: []mode{mArray},
301 action: "write"}
302 _, got := vw.WriteArrayElement()
303 if !compareErrors(got, want) {
304 t.Errorf("Did not get expected error. got %v; want %v", got, want)
305 }
306 })
307 t.Run("WriteArrayEnd", func(t *testing.T) {
308 vw := newValueWriter(ioutil.Discard)
309 vw.push(mElement)
310 want := fmt.Errorf("incorrect mode to end array: %s", mElement)
311 got := vw.WriteArrayEnd()
312 if !compareErrors(got, want) {
313 t.Errorf("Did not get expected error. got %v; want %v", got, want)
314 }
315 vw.push(mArray)
316 vw.buf = append(vw.buf, make([]byte, 1019)...)
317 maxSize = 512
318 want = errMaxDocumentSizeExceeded{size: 1024}
319 got = vw.WriteArrayEnd()
320 if !compareErrors(got, want) {
321 t.Errorf("Did not get expected error. got %v; want %v", got, want)
322 }
323 maxSize = math.MaxInt32
324 })
325
326 t.Run("WriteBytes", func(t *testing.T) {
327 t.Run("writeElementHeader error", func(t *testing.T) {
328 vw := newValueWriterFromSlice(nil)
329 want := TransitionError{current: mTopLevel, destination: mode(0),
330 name: "WriteValueBytes", modes: []mode{mElement, mValue}, action: "write"}
331 got := vw.WriteValueBytes(bsontype.EmbeddedDocument, nil)
332 if !compareErrors(got, want) {
333 t.Errorf("Did not received expected error. got %v; want %v", got, want)
334 }
335 })
336 t.Run("success", func(t *testing.T) {
337 index, doc := bsoncore.ReserveLength(nil)
338 doc = bsoncore.AppendStringElement(doc, "hello", "world")
339 doc = append(doc, 0x00)
340 doc = bsoncore.UpdateLength(doc, index, int32(len(doc)))
341
342 index, want := bsoncore.ReserveLength(nil)
343 want = bsoncore.AppendDocumentElement(want, "foo", doc)
344 want = append(want, 0x00)
345 want = bsoncore.UpdateLength(want, index, int32(len(want)))
346
347 vw := newValueWriterFromSlice(make([]byte, 0, 512))
348 _, err := vw.WriteDocument()
349 noerr(t, err)
350 _, err = vw.WriteDocumentElement("foo")
351 noerr(t, err)
352 err = vw.WriteValueBytes(bsontype.EmbeddedDocument, doc)
353 noerr(t, err)
354 err = vw.WriteDocumentEnd()
355 noerr(t, err)
356 got := vw.buf
357 if !bytes.Equal(got, want) {
358 t.Errorf("Bytes are not equal. got %v; want %v", got, want)
359 }
360 })
361 })
362 }
363
364 type errWriter struct {
365 err error
366 }
367
368 func (ew errWriter) Write([]byte) (int, error) { return 0, ew.err }
369
View as plain text