Skip to content

Commit 0cd0d3c

Browse files
authored
GODRIVER-2017 Skip empty extJSON objects correctly in Unmarshal (#677)
1 parent b0aff49 commit 0cd0d3c

File tree

2 files changed

+52
-5
lines changed

2 files changed

+52
-5
lines changed

bson/bsonrw/extjson_reader.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,23 @@ func (ejvr *extJSONValueReader) skipObject() {
164164
depth := 1
165165
for depth > 0 {
166166
ejvr.p.advanceState()
167+
168+
// If object is empty, raise depth and continue. When emptyObject is true, the
169+
// parser has already read both the opening and closing brackets of an empty
170+
// object ("{}"), so the next valid token will be part of the parent document,
171+
// not part of the nested document.
172+
//
173+
// If there is a comma, there are remaining fields, emptyObject must be set back
174+
// to false, and comma must be skipped with advanceState().
175+
if ejvr.p.emptyObject {
176+
if ejvr.p.s == jpsSawComma {
177+
ejvr.p.emptyObject = false
178+
ejvr.p.advanceState()
179+
}
180+
depth--
181+
continue
182+
}
183+
167184
switch ejvr.p.s {
168185
case jpsSawBeginObject, jpsSawBeginArray:
169186
depth++

bson/unmarshal_test.go

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ func TestUnmarshalExtJSONWithUndefinedField(t *testing.T) {
234234
// When unmarshalling extJSON, fields that are undefined in the destination struct are skipped.
235235
// This process must not skip other, defined fields and must not raise errors.
236236
type expectedResponse struct {
237-
DefinedField string
237+
DefinedField interface{}
238238
}
239239

240240
unmarshalExpectedResponse := func(t *testing.T, extJSON string) *expectedResponse {
@@ -246,98 +246,128 @@ func TestUnmarshalExtJSONWithUndefinedField(t *testing.T) {
246246
}
247247

248248
testCases := []struct {
249-
name string
250-
testJSON string
249+
name string
250+
testJSON string
251+
expectedValue interface{}
251252
}{
252253
{
253254
"no array",
254255
`{
255256
"UndefinedField": {"key": 1},
256257
"DefinedField": "value"
257258
}`,
259+
"value",
258260
},
259261
{
260262
"outer array",
261263
`{
262264
"UndefinedField": [{"key": 1}],
263265
"DefinedField": "value"
264266
}`,
267+
"value",
265268
},
266269
{
267270
"embedded array",
268271
`{
269272
"UndefinedField": {"keys": [2]},
270273
"DefinedField": "value"
271274
}`,
275+
"value",
272276
},
273277
{
274278
"outer array and embedded array",
275279
`{
276280
"UndefinedField": [{"keys": [2]}],
277281
"DefinedField": "value"
278282
}`,
283+
"value",
279284
},
280285
{
281286
"embedded document",
282287
`{
283288
"UndefinedField": {"key": {"one": "two"}},
284289
"DefinedField": "value"
285290
}`,
291+
"value",
286292
},
287293
{
288294
"doubly embedded document",
289295
`{
290296
"UndefinedField": {"key": {"one": {"two": "three"}}},
291297
"DefinedField": "value"
292298
}`,
299+
"value",
293300
},
294301
{
295302
"embedded document and embedded array",
296303
`{
297304
"UndefinedField": {"key": {"one": {"two": [3]}}},
298305
"DefinedField": "value"
299306
}`,
307+
"value",
300308
},
301309
{
302310
"embedded document and embedded array in outer array",
303311
`{
304312
"UndefinedField": [{"key": {"one": [3]}}],
305313
"DefinedField": "value"
306314
}`,
315+
"value",
307316
},
308317
{
309318
"code with scope",
310319
`{
311320
"UndefinedField": {"logic": {"$code": "foo", "$scope": {"bar": 1}}},
312321
"DefinedField": "value"
313322
}`,
323+
"value",
314324
},
315325
{
316326
"embedded array of code with scope",
317327
`{
318328
"UndefinedField": {"logic": [{"$code": "foo", "$scope": {"bar": 1}}]},
319329
"DefinedField": "value"
320330
}`,
331+
"value",
321332
},
322333
{
323334
"type definition embedded document",
324335
`{
325336
"UndefinedField": {"myDouble": {"$numberDouble": "1.24"}},
326337
"DefinedField": "value"
327338
}`,
339+
"value",
328340
},
329341
{
330342
"empty embedded document",
331343
`{
332-
"UndefinedField": {"empty": {}},
344+
"UndefinedField": {"empty": {}, "key": 1},
333345
"DefinedField": "value"
334346
}`,
347+
"value",
348+
},
349+
{
350+
"empty object before",
351+
`{
352+
"UndefinedField": {},
353+
"DefinedField": {"value": "a"}
354+
}`,
355+
D{{"value", "a"}},
356+
},
357+
{
358+
"empty object after",
359+
`{
360+
"DefinedField": {"value": "a"},
361+
"UndefinedField": {}
362+
}`,
363+
D{{"value", "a"}},
335364
},
336365
}
337366
for _, tc := range testCases {
338367
t.Run(tc.name, func(t *testing.T) {
339368
responseDoc := unmarshalExpectedResponse(t, tc.testJSON)
340-
assert.Equal(t, "value", responseDoc.DefinedField, "expected DefinedField to be 'value', got %q", responseDoc.DefinedField)
369+
assert.Equal(t, tc.expectedValue, responseDoc.DefinedField, "expected DefinedField to be %v, got %q",
370+
tc.expectedValue, responseDoc.DefinedField)
341371
})
342372
}
343373
}

0 commit comments

Comments
 (0)