1package bsonx 2 3import ( 4 "reflect" 5 "testing" 6 "time" 7 8 "github.com/google/go-cmp/cmp" 9 "go.mongodb.org/mongo-driver/bson" 10 "go.mongodb.org/mongo-driver/bson/primitive" 11 "go.mongodb.org/mongo-driver/internal/testutil/assert" 12) 13 14func TestReflectionFreeDCodec(t *testing.T) { 15 assert.RegisterOpts(reflect.TypeOf(primitive.D{}), cmp.AllowUnexported(primitive.Decimal128{})) 16 17 now := time.Now() 18 oid := primitive.NewObjectID() 19 d128 := primitive.NewDecimal128(10, 20) 20 js := primitive.JavaScript("js") 21 symbol := primitive.Symbol("sybmol") 22 binary := primitive.Binary{Subtype: 2, Data: []byte("binary")} 23 datetime := primitive.NewDateTimeFromTime(now) 24 regex := primitive.Regex{Pattern: "pattern", Options: "i"} 25 dbPointer := primitive.DBPointer{DB: "db", Pointer: oid} 26 timestamp := primitive.Timestamp{T: 5, I: 10} 27 cws := primitive.CodeWithScope{Code: js, Scope: bson.D{{"x", 1}}} 28 noReflectionRegistry := bson.NewRegistryBuilder().RegisterCodec(tPrimitiveD, ReflectionFreeDCodec).Build() 29 docWithAllTypes := primitive.D{ 30 {"byteSlice", []byte("foobar")}, 31 {"sliceByteSlice", [][]byte{[]byte("foobar")}}, 32 {"timeTime", now}, 33 {"sliceTimeTime", []time.Time{now}}, 34 {"objectID", oid}, 35 {"sliceObjectID", []primitive.ObjectID{oid}}, 36 {"decimal128", d128}, 37 {"sliceDecimal128", []primitive.Decimal128{d128}}, 38 {"js", js}, 39 {"sliceJS", []primitive.JavaScript{js}}, 40 {"symbol", symbol}, 41 {"sliceSymbol", []primitive.Symbol{symbol}}, 42 {"binary", binary}, 43 {"sliceBinary", []primitive.Binary{binary}}, 44 {"undefined", primitive.Undefined{}}, 45 {"sliceUndefined", []primitive.Undefined{{}}}, 46 {"datetime", datetime}, 47 {"sliceDateTime", []primitive.DateTime{datetime}}, 48 {"null", primitive.Null{}}, 49 {"sliceNull", []primitive.Null{{}}}, 50 {"regex", regex}, 51 {"sliceRegex", []primitive.Regex{regex}}, 52 {"dbPointer", dbPointer}, 53 {"sliceDBPointer", []primitive.DBPointer{dbPointer}}, 54 {"timestamp", timestamp}, 55 {"sliceTimestamp", []primitive.Timestamp{timestamp}}, 56 {"minKey", primitive.MinKey{}}, 57 {"sliceMinKey", []primitive.MinKey{{}}}, 58 {"maxKey", primitive.MaxKey{}}, 59 {"sliceMaxKey", []primitive.MaxKey{{}}}, 60 {"cws", cws}, 61 {"sliceCWS", []primitive.CodeWithScope{cws}}, 62 {"bool", true}, 63 {"sliceBool", []bool{true}}, 64 {"int", int(10)}, 65 {"sliceInt", []int{10}}, 66 {"int8", int8(10)}, 67 {"sliceInt8", []int8{10}}, 68 {"int16", int16(10)}, 69 {"sliceInt16", []int16{10}}, 70 {"int32", int32(10)}, 71 {"sliceInt32", []int32{10}}, 72 {"int64", int64(10)}, 73 {"sliceInt64", []int64{10}}, 74 {"uint", uint(10)}, 75 {"sliceUint", []uint{10}}, 76 {"uint8", uint8(10)}, 77 {"sliceUint8", []uint8{10}}, 78 {"uint16", uint16(10)}, 79 {"sliceUint16", []uint16{10}}, 80 {"uint32", uint32(10)}, 81 {"sliceUint32", []uint32{10}}, 82 {"uint64", uint64(10)}, 83 {"sliceUint64", []uint64{10}}, 84 {"float32", float32(10)}, 85 {"sliceFloat32", []float32{10}}, 86 {"float64", float64(10)}, 87 {"sliceFloat64", []float64{10}}, 88 {"primitiveA", primitive.A{"foo", "bar"}}, 89 } 90 91 t.Run("encode", func(t *testing.T) { 92 // Assert that bson.Marshal returns the same result when using the default registry and noReflectionRegistry. 93 94 expected, err := bson.Marshal(docWithAllTypes) 95 assert.Nil(t, err, "Marshal error with default registry: %v", err) 96 actual, err := bson.MarshalWithRegistry(noReflectionRegistry, docWithAllTypes) 97 assert.Nil(t, err, "Marshal error with noReflectionRegistry: %v", err) 98 assert.Equal(t, expected, actual, "expected doc %s, got %s", bson.Raw(expected), bson.Raw(actual)) 99 }) 100 t.Run("decode", func(t *testing.T) { 101 // Assert that bson.Unmarshal returns the same result when using the default registry and noReflectionRegistry. 102 103 // docWithAllTypes contains some types that can't be roundtripped. For example, any slices besides primitive.A 104 // would start of as []T but unmarshal to primitive.A. To get around this, we first marshal docWithAllTypes to 105 // raw bytes and then Unmarshal to another primitive.D rather than asserting directly against docWithAllTypes. 106 docBytes, err := bson.Marshal(docWithAllTypes) 107 assert.Nil(t, err, "Marshal error: %v", err) 108 109 var expected, actual primitive.D 110 err = bson.Unmarshal(docBytes, &expected) 111 assert.Nil(t, err, "Unmarshal error with default registry: %v", err) 112 err = bson.UnmarshalWithRegistry(noReflectionRegistry, docBytes, &actual) 113 assert.Nil(t, err, "Unmarshal error with noReflectionRegistry: %v", err) 114 115 assert.Equal(t, expected, actual, "expected document %v, got %v", expected, actual) 116 }) 117} 118