github.com/RevenueMonster/sqlike@v1.0.6/jsonb/decoder_test.go (about) 1 package jsonb 2 3 import ( 4 "encoding/json" 5 "reflect" 6 "testing" 7 "time" 8 9 "github.com/RevenueMonster/sqlike/reflext" 10 "github.com/stretchr/testify/require" 11 "golang.org/x/text/currency" 12 "golang.org/x/text/language" 13 ) 14 15 type CustomString string 16 17 func TestDecodeByte(t *testing.T) { 18 var ( 19 dec = DefaultDecoder{} 20 r *Reader 21 x []byte 22 b []byte 23 err error 24 ) 25 26 v := reflext.ValueOf(&x).Elem() 27 28 r = NewReader([]byte(`""`)) 29 err = dec.DecodeByte(r, v) 30 require.NoError(t, err) 31 require.Equal(t, make([]byte, 0), x) 32 33 r = NewReader([]byte(`null`)) 34 err = dec.DecodeByte(r, v) 35 require.NoError(t, err) 36 require.Equal(t, []byte(nil), x) 37 38 b = []byte(`"VGhlIGlubGluZSB0YWJsZXMgYWJvdmUgYXJlIGlkZW50aWNhbCB0byB0aGUgZm9sbG93aW5nIHN0YW5kYXJkIHRhYmxlIGRlZmluaXRpb25zOg=="`) 39 r = NewReader(b) 40 err = dec.DecodeByte(r, v) 41 require.NoError(t, err) 42 require.Equal(t, []byte(`The inline tables above are identical to the following standard table definitions:`), x) 43 } 44 45 func TestDecodeLanguage(t *testing.T) { 46 var ( 47 dec = DefaultDecoder{} 48 r *Reader 49 // tag language.Tag 50 x language.Tag 51 err error 52 ) 53 54 v := reflext.ValueOf(&x).Elem() 55 56 // r = NewReader([]byte(`""`)) 57 // err = dec.DecodeTime(r, v) 58 // require.NoError(t, err) 59 // require.Equal(t, time.Time{}, x) 60 61 { 62 r = NewReader([]byte(`"en"`)) 63 err = dec.DecodeLanguage(r, v) 64 require.NoError(t, err) 65 require.Equal(t, language.English, x) 66 } 67 } 68 69 func TestCurrency(t *testing.T) { 70 var ( 71 dec = DefaultDecoder{registry: buildDefaultRegistry()} 72 r *Reader 73 x currency.Unit 74 err error 75 ) 76 77 v := reflext.ValueOf(&x).Elem() 78 79 t.Run("Decode with null", func(ti *testing.T) { 80 r = NewReader([]byte(`null`)) 81 err = dec.DecodeCurrency(r, v) 82 require.NoError(t, err) 83 require.Equal(t, currency.Unit{}, x) 84 }) 85 86 t.Run("Decode with value", func(ti *testing.T) { 87 r = NewReader([]byte(`"USD"`)) 88 err = dec.DecodeCurrency(r, v) 89 require.NoError(t, err) 90 require.Equal(t, currency.USD, x) 91 }) 92 93 t.Run("Decode with invalid value", func(ti *testing.T) { 94 r = NewReader([]byte(`"USDT"`)) 95 err = dec.DecodeCurrency(r, v) 96 require.Error(t, err) 97 }) 98 } 99 100 func TestDecodeTime(t *testing.T) { 101 var ( 102 dec = DefaultDecoder{} 103 r *Reader 104 dt time.Time 105 x time.Time 106 err error 107 ) 108 109 v := reflext.ValueOf(&x).Elem() 110 111 r = NewReader([]byte(`""`)) 112 err = dec.DecodeTime(r, v) 113 require.NoError(t, err) 114 require.Equal(t, time.Time{}, x) 115 116 dt, _ = time.Parse("2006-01-02", "2018-01-02") 117 r = NewReader([]byte(`"2018-01-02"`)) 118 err = dec.DecodeTime(r, v) 119 require.NoError(t, err) 120 require.Equal(t, dt, x) 121 122 dt, _ = time.Parse("2006-01-02 15:04:05", "2018-01-02 13:58:26") 123 r = NewReader([]byte(`"2018-01-02 13:58:26"`)) 124 err = dec.DecodeTime(r, v) 125 require.NoError(t, err) 126 require.Equal(t, dt, x) 127 128 t.Run("Decode Time w invalid format", func(it *testing.T) { 129 r = NewReader([]byte(`"2018-01-02 13:65:66"`)) 130 err = dec.DecodeTime(r, v) 131 require.Error(it, err) 132 133 r = NewReader([]byte(`2018-01-02 13:65:66"`)) 134 err = dec.DecodeTime(r, v) 135 require.Error(it, err) 136 137 r = NewReader([]byte(`"2018-01-02 13:65:66`)) 138 err = dec.DecodeTime(r, v) 139 require.Error(it, err) 140 141 r = NewReader([]byte(``)) 142 err = dec.DecodeTime(r, v) 143 require.Error(it, err) 144 }) 145 146 } 147 148 func TestDecodeJSONRaw(t *testing.T) { 149 var ( 150 dec = DefaultDecoder{registry: buildDefaultRegistry()} 151 r *Reader 152 x json.RawMessage 153 err error 154 ) 155 156 v := reflext.ValueOf(&x).Elem() 157 158 t.Run("Decode with null", func(ti *testing.T) { 159 r = NewReader([]byte(`null`)) 160 err = dec.DecodeJSONRaw(r, v) 161 require.NoError(t, err) 162 require.Equal(t, json.RawMessage(`null`), x) 163 }) 164 165 t.Run("Decode with number", func(ti *testing.T) { 166 r = NewReader([]byte(`98`)) 167 err = dec.DecodeJSONRaw(r, v) 168 require.NoError(t, err) 169 require.Equal(t, json.RawMessage(`98`), x) 170 }) 171 } 172 173 func TestDecodeJSONNumber(t *testing.T) { 174 var ( 175 dec = DefaultDecoder{registry: buildDefaultRegistry()} 176 r *Reader 177 x json.Number 178 err error 179 ) 180 181 v := reflext.ValueOf(&x).Elem() 182 183 t.Run("Decode with null", func(ti *testing.T) { 184 r = NewReader([]byte(`null`)) 185 err = dec.DecodeJSONNumber(r, v) 186 require.NoError(t, err) 187 require.Equal(t, json.Number("0"), x) 188 }) 189 190 t.Run("Decode with position integer", func(ti *testing.T) { 191 r = NewReader([]byte(`88`)) 192 err = dec.DecodeJSONNumber(r, v) 193 require.NoError(t, err) 194 require.Equal(t, json.Number("88"), x) 195 require.Equal(t, "88", x.String()) 196 i64, _ := x.Int64() 197 require.Equal(t, int64(88), i64) 198 f64, _ := x.Float64() 199 require.Equal(t, float64(88), f64) 200 }) 201 202 t.Run("Decode json.Number w invalid value", func(ti *testing.T) { 203 r = NewReader([]byte(`hsdjdkd`)) 204 err = dec.DecodeJSONNumber(r, v) 205 require.Error(t, err) 206 207 // r = NewReader([]byte(`10.3a`)) 208 // err = dec.DecodeJSONNumber(r, v) 209 // require.Error(t, err) 210 }) 211 } 212 213 func TestDecodeMap(t *testing.T) { 214 var ( 215 dec = DefaultDecoder{registry: buildDefaultRegistry()} 216 r *Reader 217 x map[string]interface{} 218 err error 219 ) 220 221 v := reflext.ValueOf(&x).Elem() 222 223 t.Run("Decode with null", func(ti *testing.T) { 224 r = NewReader([]byte(`null`)) 225 err = dec.DecodeMap(r, v) 226 require.NoError(t, err) 227 require.Equal(t, map[string]interface{}(nil), x) 228 }) 229 230 t.Run("Decode with empty object", func(ti *testing.T) { 231 r = NewReader([]byte(`{}`)) 232 err = dec.DecodeMap(r, v) 233 require.NoError(t, err) 234 require.Equal(t, make(map[string]interface{}), x) 235 }) 236 237 t.Run("Decode to map<string,interface{}>", func(ti *testing.T) { 238 r = NewReader([]byte(` 239 { 240 "a":"123", 241 "b": 108213312, 242 "c": true, 243 "d": "alSLKaj28173-021@#$%^&*\"", 244 "e": 0.3127123 245 }`)) 246 err = dec.DecodeMap(r, v) 247 require.NoError(t, err) 248 require.Equal(t, map[string]interface{}{ 249 "a": "123", 250 "b": float64(108213312), 251 "c": true, 252 "d": `alSLKaj28173-021@#$%^&*"`, 253 "e": float64(0.3127123), 254 }, x) 255 256 }) 257 258 t.Run("Decode to map<string,string>", func(ti *testing.T) { 259 r = NewReader([]byte(` 260 { 261 "number": "1234567890", 262 "b":"abcdefghijklmnopqrstuvwxyz", 263 "emoji": "๐ ๐ ๐ ๐คฃ ๐ ๐ ๐ ๐ ๐ ๐", 264 "japanese": "็ฆๅฒกๅธ็พ่ก้คจใงๅค้้้คจในใฟใผใ๏ผ7ๆ๏ฝ10ๆใฎ้ๆๆฅใจๅๆๆฅใฏ20ๆใพใงๅปถ้ท้้คจ" 265 }`)) 266 m := make(map[string]string) 267 v := reflect.ValueOf(&m) 268 err = dec.DecodeMap(r, v.Elem()) 269 require.NoError(ti, err) 270 require.Equal(ti, map[string]string{ 271 "number": "1234567890", 272 "b": "abcdefghijklmnopqrstuvwxyz", 273 "emoji": "๐ ๐ ๐ ๐คฃ ๐ ๐ ๐ ๐ ๐ ๐", 274 "japanese": "็ฆๅฒกๅธ็พ่ก้คจใงๅค้้้คจในใฟใผใ๏ผ7ๆ๏ฝ10ๆใฎ้ๆๆฅใจๅๆๆฅใฏ20ๆใพใงๅปถ้ท้้คจ", 275 }, m) 276 }) 277 278 t.Run("Decode to map<string,bool>", func(ti *testing.T) { 279 r = NewReader([]byte(` 280 { 281 "true": true, 282 "false": false 283 }`)) 284 m := make(map[string]bool) 285 v := reflect.ValueOf(&m) 286 err = dec.DecodeMap(r, v.Elem()) 287 require.NoError(ti, err) 288 require.Equal(ti, map[string]bool{ 289 "true": true, 290 "false": false, 291 }, m) 292 }) 293 294 t.Run("Decode to map<string,int>", func(ti *testing.T) { 295 r = NewReader([]byte(` 296 { 297 "minus-one": -1, 298 "negative": -31231237, 299 "one": 1, 300 "two":2, 301 "eleven": 11, 302 "hundred": 100 303 }`)) 304 m := make(map[string]int) 305 v := reflect.ValueOf(&m) 306 err = dec.DecodeMap(r, v.Elem()) 307 require.NoError(ti, err) 308 require.Equal(ti, map[string]int{ 309 "minus-one": -1, 310 "negative": -31231237, 311 "one": 1, 312 "two": 2, 313 "eleven": 11, 314 "hundred": 100, 315 }, m) 316 }) 317 318 t.Run("Decode to map<string,uint8>", func(ti *testing.T) { 319 r = NewReader([]byte(` 320 { 321 "one": 1, 322 "two":2, 323 "eleven": 11, 324 "hundred": 100 325 }`)) 326 m := make(map[string]uint8) 327 v := reflect.ValueOf(&m) 328 err = dec.DecodeMap(r, v.Elem()) 329 require.NoError(ti, err) 330 require.Equal(ti, map[string]uint8{ 331 "one": 1, 332 "two": 2, 333 "eleven": 11, 334 "hundred": 100, 335 }, m) 336 }) 337 338 t.Run("Decode to map<string,float32>", func(ti *testing.T) { 339 r = NewReader([]byte(` 340 { 341 "minus-one": -1, 342 "negative": -31231237, 343 "one": 1, 344 "two":2, 345 "eleven": 11, 346 "hundred": 100, 347 "number": 3123123799213, 348 }`)) 349 m := make(map[string]float32) 350 v := reflect.ValueOf(&m) 351 err = dec.DecodeMap(r, v.Elem()) 352 require.NoError(ti, err) 353 require.Equal(ti, map[string]float32{ 354 "minus-one": -1, 355 "negative": -31231237, 356 "one": 1, 357 "two": 2, 358 "eleven": 11, 359 "hundred": 100, 360 "number": 3123123799213, 361 }, m) 362 }) 363 364 t.Run("Decode to map<string,float64>", func(ti *testing.T) { 365 r = NewReader([]byte(` 366 { 367 "minus-one": -1, 368 "negative": -3123123799213, 369 "one": 1, 370 "two":2, 371 "eleven": 11, 372 "hundred": 100, 373 "number": 3123123799213, 374 }`)) 375 m := make(map[string]float64) 376 v := reflect.ValueOf(&m) 377 err = dec.DecodeMap(r, v.Elem()) 378 require.NoError(ti, err) 379 require.Equal(ti, map[string]float64{ 380 "minus-one": -1, 381 "negative": -3123123799213, 382 "one": 1, 383 "two": 2, 384 "eleven": 11, 385 "hundred": 100, 386 "number": 3123123799213, 387 }, m) 388 }) 389 390 t.Run("Decode to map<string,interface{}>", func(ti *testing.T) { 391 r = NewReader([]byte(` 392 { 393 "negative": -183, 394 "string": "textasjdhasljdlasjkdjlsa:'dasdas", 395 "number": 3123123799213, 396 "nested": { 397 "k": { 398 "bool": true, 399 "no": 10, 400 "string": "๐๐๐" 401 } 402 } 403 }`)) 404 m := make(map[string]interface{}) 405 v := reflect.ValueOf(&m) 406 err = dec.DecodeMap(r, v.Elem()) 407 require.NoError(ti, err) 408 require.Equal(ti, map[string]interface{}{ 409 "negative": float64(-183), 410 "string": "textasjdhasljdlasjkdjlsa:'dasdas", 411 "number": float64(3123123799213), 412 "nested": map[string]interface{}{ 413 "k": map[string]interface{}{ 414 "bool": true, 415 "no": float64(10), 416 "string": "๐๐๐", 417 }, 418 }, 419 }, m) 420 }) 421 422 t.Run("Decode to map[CustomString]*string", func(ti *testing.T) { 423 var m map[CustomString]*string 424 425 r = NewReader([]byte(` 426 { 427 "0": "zero", 428 "1": "one", 429 "2": "two", 430 "3": "three" 431 }`)) 432 433 v := reflect.ValueOf(&m) 434 err = dec.DecodeMap(r, v.Elem()) 435 require.NoError(ti, err) 436 zero, one, two, three := "zero", "one", "two", "three" 437 require.Equal(t, map[CustomString]*string{ 438 CustomString("0"): &zero, 439 CustomString("1"): &one, 440 CustomString("2"): &two, 441 CustomString("3"): &three, 442 }, m) 443 }) 444 445 t.Run("Decode with unsupported data type", func(ti *testing.T) { 446 var mx map[*CustomString]string 447 r = NewReader([]byte(` 448 { 449 "0": "zero", 450 "1": "one", 451 "2": "two", 452 "3": "three" 453 }`)) 454 v = reflect.ValueOf(&mx) 455 err = dec.DecodeMap(r, v.Elem()) 456 require.Error(ti, err) 457 }) 458 459 } 460 461 func TestDecodeArray(t *testing.T) { 462 var ( 463 err error 464 ) 465 466 t.Run("Decode to [2]string", func(ti *testing.T) { 467 arr := [2]string{} 468 err = Unmarshal([]byte(`["test", "abc", "ddd"]`), &arr) 469 require.Error(ti, err) 470 471 err = Unmarshal([]byte(`["ไบฌ้ฝ็็ฉใฌใณใฟใซๅคข้คจ", "aBcdEfgHiJklmnO"]`), &arr) 472 require.NoError(ti, err) 473 require.ElementsMatch(ti, [...]string{ 474 "ไบฌ้ฝ็็ฉใฌใณใฟใซๅคข้คจ", 475 "aBcdEfgHiJklmnO", 476 }, arr) 477 }) 478 479 t.Run("Decode to []int", func(ti *testing.T) { 480 arr := []int{} 481 err = Unmarshal([]byte(`[1, "xdd", 3]`), &arr) 482 require.Error(ti, err) 483 484 err = Unmarshal([]byte(`[1, 88, 3, -1992, 9999]`), &arr) 485 require.NoError(ti, err) 486 require.ElementsMatch(t, []int{1, 88, 3, -1992, 9999}, arr) 487 }) 488 489 t.Run("Decode to []struct{}", func(it *testing.T) { 490 type Region struct { 491 DialingCode int 492 CountryCode string 493 } 494 495 type Contact struct { 496 Name string 497 LangCode language.Tag 498 PhoneNumber string 499 IsPrimary bool 500 Region Region 501 } 502 503 type Address struct { 504 Remark string 505 Address string 506 Contact Contact 507 FloorNumber string 508 BuildingNumber string 509 EntranceNumber string 510 } 511 512 addrs := []Address{} 513 b := []byte(`{hsh:""}`) 514 err = Unmarshal(b, &addrs) 515 require.Error(t, err) 516 517 b = []byte(`[ 518 { 519 "Remark": "One Utama, 1 UTAMA SHOPPING CENTRE, LEBUH BANDAR UTAMA, BANDAR UTAMA", 520 "Address": "1 UTAMA SHOPPING CENTRE, LEBUH BANDAR UTAMA, BANDAR UTAMA, KOTA DAMANSARA PETALING JAYA, 47800, Petaling Jaya, Selangor, Malaysia", 521 "Contact": { 522 "Name": "One Utama", 523 "PhoneNumber": "60176473298" 524 }, 525 "FloorNumber": "", 526 "BuildingNumber": "", 527 "EntranceNumber": "" 528 }, 529 { 530 "Remark": "", 531 "Address": "Gugusan Melur, Kota Damansara, 47810, Petaling Jaya, Selangor, Malaysia", 532 "Contact": { 533 "Name": "Mohamed Yussuf", 534 "PhoneNumber": "60176473298", 535 "IsPrimary": true, 536 "Region": { 537 "DialingCode": 60, 538 "CountryCode": "MY" 539 } 540 }, 541 "FloorNumber": "", 542 "BuildingNumber": "", 543 "EntranceNumber": "" 544 } 545 ]`) 546 547 addrs = []Address{} // reset address 548 err = Unmarshal(b, &addrs) 549 require.NoError(t, err) 550 551 require.ElementsMatch(t, []Address{ 552 { 553 Address: "1 UTAMA SHOPPING CENTRE, LEBUH BANDAR UTAMA, BANDAR UTAMA, KOTA DAMANSARA PETALING JAYA, 47800, Petaling Jaya, Selangor, Malaysia", 554 Remark: "One Utama, 1 UTAMA SHOPPING CENTRE, LEBUH BANDAR UTAMA, BANDAR UTAMA", 555 Contact: Contact{ 556 Name: "One Utama", 557 PhoneNumber: "60176473298", 558 }, 559 }, 560 { 561 Address: "Gugusan Melur, Kota Damansara, 47810, Petaling Jaya, Selangor, Malaysia", 562 Contact: Contact{ 563 Name: "Mohamed Yussuf", 564 PhoneNumber: "60176473298", 565 IsPrimary: true, 566 Region: Region{ 567 DialingCode: 60, 568 CountryCode: "MY", 569 }, 570 }, 571 }, 572 }, addrs) 573 }) 574 }