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