github.com/zerosnake0/jzon@v0.0.9-0.20230801092939-1b135cb83f7f/val_decoder_native_struct_test.go (about) 1 package jzon 2 3 import ( 4 "io" 5 "runtime/debug" 6 "testing" 7 8 "github.com/stretchr/testify/require" 9 ) 10 11 func TestValDecoder_Native_Struct_Zero_Field(t *testing.T) { 12 f := func(t *testing.T, data string, ex error, p1, p2 interface{}) { 13 checkDecodeWithStandard(t, DefaultDecoderConfig, data, ex, p1, p2) 14 } 15 t.Run("nil receiver", func(t *testing.T) { 16 f(t, "null", ErrNilPointerReceiver, nil, nil) 17 }) 18 t.Run("eof", func(t *testing.T) { 19 f(t, "", io.EOF, &struct{}{}, &struct{}{}) 20 }) 21 t.Run("null", func(t *testing.T) { 22 f(t, "null", nil, &struct{}{}, &struct{}{}) 23 }) 24 t.Run("invalid first byte", func(t *testing.T) { 25 f(t, "+", UnexpectedByteError{}, &struct{}{}, &struct{}{}) 26 }) 27 debug.FreeOSMemory() 28 } 29 30 func TestValDecoder_Native_Struct_Mapping(t *testing.T) { 31 f := func(t *testing.T, data string, ex error, p1, p2 interface{}) { 32 checkDecodeWithStandard(t, DefaultDecoderConfig, data, ex, p1, p2) 33 } 34 t.Run("unexported field", func(t *testing.T) { 35 f(t, ` { "a" : "abc" } `, nil, &struct { 36 a string 37 }{}, &struct { 38 a string 39 }{}) 40 }) 41 t.Run("unexported field 2", func(t *testing.T) { 42 f(t, ` { "a" : "abc" } `, nil, &struct { 43 a string 44 B int 45 }{}, &struct { 46 a string 47 B int 48 }{}) 49 }) 50 t.Run("tag ignored 1", func(t *testing.T) { 51 f(t, ` { "A" : "abc" } `, nil, &struct { 52 A string `json:"-"` 53 }{A: "test"}, &struct { 54 A string `json:"-"` 55 }{A: "test"}) 56 }) 57 t.Run("tag", func(t *testing.T) { 58 f(t, ` { "b" : "abc" } `, nil, &struct { 59 A string `json:"B"` 60 }{A: "test"}, &struct { 61 A string `json:"B"` 62 }{A: "test"}) 63 }) 64 t.Run("case insensitive", func(t *testing.T) { 65 f(t, ` { "a" : "abc" } `, nil, &struct { 66 A string 67 }{A: "test"}, &struct { 68 A string 69 }{A: "test"}) 70 }) 71 t.Run("case insensitive 2", func(t *testing.T) { 72 f(t, ` { "A" : "abc" } `, nil, &struct { 73 A string `json:"a"` 74 }{A: "test"}, &struct { 75 A string `json:"a"` 76 }{A: "test"}) 77 }) 78 t.Run("multiple same key", func(t *testing.T) { 79 f(t, ` { "a" : "abc" , "a" : "def" } `, nil, &struct { 80 A string `json:"a"` 81 }{A: "test"}, &struct { 82 A string `json:"a"` 83 }{A: "test"}) 84 }) 85 debug.FreeOSMemory() 86 } 87 88 func TestValDecoder_Native_Struct(t *testing.T) { 89 f := func(t *testing.T, data string, ex error, p1, p2 interface{}) { 90 checkDecodeWithStandard(t, DefaultDecoderConfig, data, ex, p1, p2) 91 } 92 t.Run("nil receiver", func(t *testing.T) { 93 f(t, "null", ErrNilPointerReceiver, nil, nil) 94 }) 95 t.Run("eof", func(t *testing.T) { 96 f(t, "", io.EOF, &struct { 97 A string 98 }{A: "test"}, &struct { 99 A string 100 }{A: "test"}) 101 }) 102 t.Run("invalid first byte", func(t *testing.T) { 103 f(t, "+", UnexpectedByteError{}, &struct { 104 A string 105 }{A: "test"}, &struct { 106 A string 107 }{A: "test"}) 108 }) 109 t.Run("invalid null", func(t *testing.T) { 110 f(t, "nul", io.EOF, &struct { 111 A string 112 }{A: "test"}, &struct { 113 A string 114 }{A: "test"}) 115 }) 116 t.Run("null", func(t *testing.T) { 117 f(t, "null", nil, &struct { 118 A string 119 }{A: "test"}, &struct { 120 A string 121 }{A: "test"}) 122 }) 123 t.Run("eof after bracket", func(t *testing.T) { 124 f(t, "{", io.EOF, &struct { 125 A string 126 }{A: "test"}, &struct { 127 A string 128 }{A: "test"}) 129 }) 130 t.Run("empty object", func(t *testing.T) { 131 f(t, " { } ", nil, &struct { 132 A string 133 }{A: "test"}, &struct { 134 A string 135 }{A: "test"}) 136 }) 137 t.Run("invalid char after bracket", func(t *testing.T) { 138 f(t, " { { ", UnexpectedByteError{}, &struct { 139 A string 140 }{A: "test"}, &struct { 141 A string 142 }{A: "test"}) 143 }) 144 t.Run("invalid field", func(t *testing.T) { 145 f(t, ` { " `, io.EOF, &struct { 146 A string 147 }{A: "test"}, &struct { 148 A string 149 }{A: "test"}) 150 }) 151 t.Run("invalid field type", func(t *testing.T) { 152 f(t, ` { "A" : 1 } `, UnexpectedByteError{}, &struct { 153 A string 154 }{A: "test"}, &struct { 155 A string 156 }{A: "test"}) 157 }) 158 t.Run("field skip error", func(t *testing.T) { 159 f(t, ` { "b" : } `, UnexpectedByteError{}, &struct { 160 A string 161 }{A: "test"}, &struct { 162 A string 163 }{A: "test"}) 164 }) 165 t.Run("more field eof", func(t *testing.T) { 166 f(t, ` { "b" : 1 `, io.EOF, &struct { 167 A string 168 }{A: "test"}, &struct { 169 A string 170 }{A: "test"}) 171 }) 172 t.Run("non empty", func(t *testing.T) { 173 f(t, ` { "a" : "abc" } `, nil, &struct { 174 A string 175 }{A: "test"}, &struct { 176 A string 177 }{A: "test"}) 178 }) 179 t.Run("more field eof after comma", func(t *testing.T) { 180 f(t, ` { "b" : 1 , `, io.EOF, &struct { 181 A string 182 }{A: "test"}, &struct { 183 A string 184 }{A: "test"}) 185 }) 186 t.Run("more field invalid byte after comma", func(t *testing.T) { 187 f(t, ` { "b" : 1 , } `, UnexpectedByteError{}, &struct { 188 A string 189 }{A: "test"}, &struct { 190 A string 191 }{A: "test"}) 192 }) 193 t.Run("more field invalid comma", func(t *testing.T) { 194 f(t, ` { "b" : 1 { `, UnexpectedByteError{}, &struct { 195 A string 196 }{A: "test"}, &struct { 197 A string 198 }{A: "test"}) 199 }) 200 t.Run("two fields", func(t *testing.T) { 201 f(t, ` { "b" : 1 , "a" : "abc" } `, nil, &struct { 202 A string 203 }{A: "test"}, &struct { 204 A string 205 }{A: "test"}) 206 }) 207 debug.FreeOSMemory() 208 } 209 210 type testStruct struct { 211 A *testStruct `json:"a"` 212 C *int `json:"c"` 213 B *testStruct `json:"b"` 214 } 215 216 func TestValDecoder_Native_Struct_Nested(t *testing.T) { 217 f := func(t *testing.T, data string, ex error, p1, p2 interface{}) { 218 checkDecodeWithStandard(t, DefaultDecoderConfig, data, ex, p1, p2) 219 } 220 t.Run("nested", func(t *testing.T) { 221 f(t, `{"a":null,"c":1,"b":{}}`, nil, &testStruct{ 222 A: &testStruct{}, 223 }, &testStruct{ 224 A: &testStruct{}, 225 }) 226 }) 227 debug.FreeOSMemory() 228 } 229 230 func TestValDecoder_Native_Struct_CustomTag(t *testing.T) { 231 decCfg := NewDecoderConfig(&DecoderOption{ 232 Tag: "jzon", 233 }) 234 var p struct { 235 A string `jzon:"b"` 236 } 237 err := decCfg.Unmarshal([]byte(` { "b" : "c" }`), &p) 238 require.NoError(t, err) 239 require.Equal(t, "c", p.A) 240 } 241 242 func TestValDecoder_Native_Struct_Embedded_Unexported(t *testing.T) { 243 f := func(t *testing.T, data string, ex error, p1, p2 interface{}) { 244 checkDecodeWithStandard(t, DefaultDecoderConfig, data, ex, p1, p2) 245 } 246 t.Run("not embedded", func(t *testing.T) { 247 type inner struct{} 248 type outer struct { 249 inner inner 250 } 251 f(t, `{"inner":{}}`, nil, &outer{}, &outer{}) 252 }) 253 t.Run("non struct", func(t *testing.T) { 254 type inner int 255 type outer struct { 256 inner 257 } 258 f(t, `{"inner":1}`, nil, &outer{}, &outer{}) 259 }) 260 t.Run("nil pointer receiver", func(t *testing.T) { 261 t.Run("duplicate field", func(t *testing.T) { 262 type inner struct { 263 A int `json:"a"` 264 } 265 type inner2 inner 266 type outer struct { 267 *inner 268 *inner2 269 } 270 f(t, `{"a":1}`, nil, &outer{}, &outer{}) 271 }) 272 t.Run("field not matched", func(t *testing.T) { 273 type inner struct { 274 B int 275 } 276 type outer struct { 277 *inner 278 } 279 f(t, `{"a":1}`, nil, &outer{}, &outer{}) 280 }) 281 t.Run("field matched", func(t *testing.T) { 282 type inner struct { 283 A int 284 } 285 type outer struct { 286 *inner 287 } 288 f(t, `{"a":1}`, ErrNilEmbeddedPointer, &outer{}, &outer{}) 289 }) 290 t.Run("exported field", func(t *testing.T) { 291 type Inner struct { 292 A int 293 } 294 type outer struct { 295 *Inner 296 } 297 f(t, `{"a":1}`, nil, &outer{}, &outer{}) 298 }) 299 }) 300 } 301 302 func TestValDecoder_Native_Struct_DisallowUnknownFields(t *testing.T) { 303 decCfg := NewDecoderConfig(&DecoderOption{ 304 DisallowUnknownFields: true, 305 }) 306 t.Run("zero field", func(t *testing.T) { 307 t.Run("eof", func(t *testing.T) { 308 var st struct{} 309 err := decCfg.Unmarshal([]byte(""), &st) 310 checkError(t, io.EOF, err) 311 }) 312 t.Run("invalid", func(t *testing.T) { 313 var st struct{} 314 err := decCfg.Unmarshal([]byte("["), &st) 315 checkError(t, UnexpectedByteError{}, err) 316 }) 317 t.Run("null", func(t *testing.T) { 318 var st struct{} 319 err := decCfg.Unmarshal([]byte("null"), &st) 320 require.NoError(t, err) 321 }) 322 t.Run("eof after bracket", func(t *testing.T) { 323 var st struct{} 324 err := decCfg.Unmarshal([]byte("{"), &st) 325 checkError(t, io.EOF, err) 326 }) 327 t.Run("non empty", func(t *testing.T) { 328 var st struct{} 329 err := decCfg.Unmarshal([]byte(`{"a":1}`), &st) 330 checkError(t, UnexpectedByteError{}, err) 331 }) 332 t.Run("empty", func(t *testing.T) { 333 var st struct{} 334 err := decCfg.Unmarshal([]byte(` { } `), &st) 335 require.NoError(t, err) 336 }) 337 }) 338 t.Run("one field", func(t *testing.T) { 339 t.Run("empty", func(t *testing.T) { 340 var st struct { 341 A int 342 } 343 err := decCfg.Unmarshal([]byte(` { } `), &st) 344 require.NoError(t, err) 345 }) 346 t.Run("non empty", func(t *testing.T) { 347 var st struct { 348 A int 349 } 350 err := decCfg.Unmarshal([]byte(` { "b" : 1 } `), &st) 351 checkError(t, UnknownFieldError(""), err) 352 }) 353 }) 354 } 355 356 func TestValDecoder_Native_Struct_Quoted(t *testing.T) { 357 f := func(t *testing.T, data string, ex error, p1, p2 interface{}) { 358 checkDecodeWithStandard(t, DefaultDecoderConfig, data, ex, p1, p2) 359 } 360 t.Run("string", func(t *testing.T) { 361 type st struct { 362 A string `json:",string"` 363 } 364 f2 := func(t *testing.T, data string, ex error) { 365 f(t, data, ex, &st{A: "test"}, &st{A: "test"}) 366 } 367 t.Run("null", func(t *testing.T) { 368 f2(t, `{"a":null}`, nil) 369 }) 370 t.Run("null string", func(t *testing.T) { 371 f2(t, `{"a":"null"}`, nil) 372 }) 373 t.Run("leading space", func(t *testing.T) { 374 f2(t, `{"a":" 1"}`, BadQuotedStringError("")) 375 }) 376 t.Run("trailing space", func(t *testing.T) { 377 f2(t, `{"a":"1 "}`, BadQuotedStringError("")) 378 }) 379 t.Run("empty", func(t *testing.T) { 380 f2(t, `{"a":""}`, BadQuotedStringError("")) 381 }) 382 t.Run("not string", func(t *testing.T) { 383 f2(t, `{"a":"1"}`, BadQuotedStringError("")) 384 }) 385 t.Run("bad string", func(t *testing.T) { 386 f2(t, `{"a":"\"\"\""}`, BadQuotedStringError("")) 387 }) 388 t.Run("ok", func(t *testing.T) { 389 f2(t, `{"a":"\"null\""}`, nil) 390 }) 391 }) 392 t.Run("int", func(t *testing.T) { 393 type stI8 struct { 394 A int8 `json:",string"` 395 } 396 type stI16 struct { 397 A int16 `json:",string"` 398 } 399 type stI32 struct { 400 A int32 `json:",string"` 401 } 402 type stI64 struct { 403 A int64 `json:",string"` 404 } 405 type stU8 struct { 406 A uint8 `json:",string"` 407 } 408 type stU16 struct { 409 A uint16 `json:",string"` 410 } 411 type stU32 struct { 412 A uint32 `json:",string"` 413 } 414 type stU64 struct { 415 A uint64 `json:",string"` 416 } 417 f2 := func(t *testing.T, data string, ex error) { 418 f(t, data, ex, &stI8{A: 2}, &stI8{A: 2}) 419 f(t, data, ex, &stI16{A: 2}, &stI16{A: 2}) 420 f(t, data, ex, &stI32{A: 2}, &stI32{A: 2}) 421 f(t, data, ex, &stI64{A: 2}, &stI64{A: 2}) 422 f(t, data, ex, &stU8{A: 2}, &stU8{A: 2}) 423 f(t, data, ex, &stU16{A: 2}, &stU16{A: 2}) 424 f(t, data, ex, &stU32{A: 2}, &stU32{A: 2}) 425 f(t, data, ex, &stU64{A: 2}, &stU64{A: 2}) 426 } 427 t.Run("unquoted", func(t *testing.T) { 428 f2(t, `{"a":1}`, UnexpectedByteError{}) 429 }) 430 t.Run("leading space", func(t *testing.T) { 431 f2(t, `{"a":" 1"}`, InvalidDigitError{}) 432 }) 433 t.Run("leading eof", func(t *testing.T) { 434 f2(t, `{"a":"`, io.EOF) 435 }) 436 t.Run("trailing space", func(t *testing.T) { 437 f2(t, `{"a":"1 "}`, UnexpectedByteError{}) 438 }) 439 t.Run("trailing eof", func(t *testing.T) { 440 f2(t, `{"a":"1`, io.EOF) 441 }) 442 t.Run("empty", func(t *testing.T) { 443 f2(t, `{"a":""}`, InvalidDigitError{}) 444 }) 445 t.Run("ok", func(t *testing.T) { 446 f2(t, `{"a":"1"}`, nil) 447 }) 448 }) 449 }