@@ -13,6 +13,8 @@ import (
13
13
"github.com/google/go-cmp/cmp"
14
14
"go.mongodb.org/mongo-driver/bson/bsoncodec"
15
15
"go.mongodb.org/mongo-driver/bson/bsonrw"
16
+ "go.mongodb.org/mongo-driver/internal/testutil/assert"
17
+ "go.mongodb.org/mongo-driver/x/bsonx/bsoncore"
16
18
)
17
19
18
20
func TestUnmarshal (t * testing.T ) {
@@ -106,3 +108,61 @@ func TestUnmarshalExtJSONWithContext(t *testing.T) {
106
108
}
107
109
})
108
110
}
111
+
112
+ func TestCachingDecodersNotSharedAcrossRegistries (t * testing.T ) {
113
+ // Decoders that have caches for recursive decoder lookup should not be shared across Registry instances. Otherwise,
114
+ // the first DecodeValue call would cache an decoder and a subsequent call would see that decoder even if a
115
+ // different Registry is used.
116
+
117
+ // Create a custom Registry that negates BSON int32 values when decoding.
118
+ var decodeInt32 bsoncodec.ValueDecoderFunc = func (_ bsoncodec.DecodeContext , vr bsonrw.ValueReader , val reflect.Value ) error {
119
+ i32 , err := vr .ReadInt32 ()
120
+ if err != nil {
121
+ return err
122
+ }
123
+
124
+ val .SetInt (int64 (- 1 * i32 ))
125
+ return nil
126
+ }
127
+ customReg := NewRegistryBuilder ().
128
+ RegisterTypeDecoder (tInt32 , bsoncodec .ValueDecoderFunc (decodeInt32 )).
129
+ Build ()
130
+
131
+ docBytes := bsoncore .BuildDocumentFromElements (
132
+ nil ,
133
+ bsoncore .AppendInt32Element (nil , "x" , 1 ),
134
+ )
135
+
136
+ // For all sub-tests, unmarshal docBytes into a struct and assert that value for "x" is 1 when using the default
137
+ // registry and -1 when using the custom registry.
138
+ t .Run ("struct" , func (t * testing.T ) {
139
+ type Struct struct {
140
+ X int32
141
+ }
142
+
143
+ var first Struct
144
+ err := Unmarshal (docBytes , & first )
145
+ assert .Nil (t , err , "Unmarshal error: %v" , err )
146
+ assert .Equal (t , int32 (1 ), first .X , "expected X value to be 1, got %v" , first .X )
147
+
148
+ var second Struct
149
+ err = UnmarshalWithRegistry (customReg , docBytes , & second )
150
+ assert .Nil (t , err , "Unmarshal error: %v" , err )
151
+ assert .Equal (t , int32 (- 1 ), second .X , "expected X value to be -1, got %v" , second .X )
152
+ })
153
+ t .Run ("pointer" , func (t * testing.T ) {
154
+ type Struct struct {
155
+ X * int32
156
+ }
157
+
158
+ var first Struct
159
+ err := Unmarshal (docBytes , & first )
160
+ assert .Nil (t , err , "Unmarshal error: %v" , err )
161
+ assert .Equal (t , int32 (1 ), * first .X , "expected X value to be 1, got %v" , * first .X )
162
+
163
+ var second Struct
164
+ err = UnmarshalWithRegistry (customReg , docBytes , & second )
165
+ assert .Nil (t , err , "Unmarshal error: %v" , err )
166
+ assert .Equal (t , int32 (- 1 ), * second .X , "expected X value to be -1, got %v" , * second .X )
167
+ })
168
+ }
0 commit comments