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