@@ -3,6 +3,7 @@ package decoder
3
3
import (
4
4
"testing"
5
5
6
+ "github.com/stretchr/testify/assert"
6
7
"github.com/stretchr/testify/require"
7
8
)
8
9
@@ -220,3 +221,82 @@ func TestNestedUnmarshalerInMap(t *testing.T) {
220
221
require .Equal (t , "map:value2" , result ["key2" ].Data )
221
222
})
222
223
}
224
+
225
+ // testMapIterator uses ReadMap() iterator to simulate mmdbtype.Map behavior.
226
+ type testMapIterator struct {
227
+ Values map [string ]string
228
+ custom bool
229
+ }
230
+
231
+ func (m * testMapIterator ) UnmarshalMaxMindDB (d * Decoder ) error {
232
+ m .custom = true
233
+ iter , size , err := d .ReadMap ()
234
+ if err != nil {
235
+ return err
236
+ }
237
+
238
+ m .Values = make (map [string ]string , size )
239
+ for key , iterErr := range iter {
240
+ if iterErr != nil {
241
+ return iterErr
242
+ }
243
+
244
+ // Read the value as a string
245
+ value , err := d .ReadString ()
246
+ if err != nil {
247
+ return err
248
+ }
249
+
250
+ m .Values [string (key )] = value
251
+ }
252
+ return nil
253
+ }
254
+
255
+ // TestCustomUnmarshalerWithIterator tests that custom unmarshalers using iterators
256
+ // work correctly in struct fields. This reproduces the original "no next offset available"
257
+ // issue that occurred when mmdbtype.Map was used in structs.
258
+ func TestCustomUnmarshalerWithIterator (t * testing.T ) {
259
+ type Record struct {
260
+ Name string
261
+ Location testMapIterator // This field uses ReadMap() iterator
262
+ Country string
263
+ }
264
+
265
+ data := []byte {
266
+ // Map with 3 items
267
+ 0xe3 ,
268
+ // Key "Name"
269
+ 0x44 , 'N' , 'a' , 'm' , 'e' ,
270
+ // Value "Test" (string)
271
+ 0x44 , 'T' , 'e' , 's' , 't' ,
272
+ // Key "Location"
273
+ 0x48 , 'L' , 'o' , 'c' , 'a' , 't' , 'i' , 'o' , 'n' ,
274
+ // Value: Map with 2 items (latitude and longitude)
275
+ 0xe2 ,
276
+ // Key "lat"
277
+ 0x43 , 'l' , 'a' , 't' ,
278
+ // Value "40.7"
279
+ 0x44 , '4' , '0' , '.' , '7' ,
280
+ // Key "lng"
281
+ 0x43 , 'l' , 'n' , 'g' ,
282
+ // Value "-74.0"
283
+ 0x45 , '-' , '7' , '4' , '.' , '0' ,
284
+ // Key "Country"
285
+ 0x47 , 'C' , 'o' , 'u' , 'n' , 't' , 'r' , 'y' ,
286
+ // Value "US"
287
+ 0x42 , 'U' , 'S' ,
288
+ }
289
+
290
+ d := New (data )
291
+ var result Record
292
+
293
+ err := d .Decode (0 , & result )
294
+ require .NoError (t , err )
295
+
296
+ require .Equal (t , "Test" , result .Name )
297
+ assert .True (t , result .Location .custom , "Custom unmarshaler should be called" )
298
+ assert .Len (t , result .Location .Values , 2 )
299
+ assert .Equal (t , "40.7" , result .Location .Values ["lat" ])
300
+ assert .Equal (t , "-74.0" , result .Location .Values ["lng" ])
301
+ assert .Equal (t , "US" , result .Country )
302
+ }
0 commit comments