github.com/trim21/go-phpserialize@v0.0.22-0.20240301204449-2fca0319b3f0/unmarshal_test.go (about) 1 package phpserialize_test 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/require" 7 8 "github.com/trim21/go-phpserialize" 9 ) 10 11 func TestUnmarshal_as_string(t *testing.T) { 12 t.Parallel() 13 14 t.Run("ptr", func(t *testing.T) { 15 type Container struct { 16 V *int `php:",omitempty,string"` 17 } 18 19 var c Container 20 raw := `a:1:{s:1:"V";s:1:"1";}` 21 err := phpserialize.Unmarshal([]byte(raw), &c) 22 require.NoError(t, err) 23 require.Equal(t, 1, *c.V) 24 }) 25 } 26 27 func TestUnmarshal_struct_string(t *testing.T) { 28 t.Parallel() 29 30 t.Run("value", func(t *testing.T) { 31 type Container struct { 32 F string `php:"f1q"` 33 V bool `php:"1a9"` 34 } 35 36 var c Container 37 raw := `a:1:{s:3:"f1q";s:10:"0147852369";}` 38 err := phpserialize.Unmarshal([]byte(raw), &c) 39 require.NoError(t, err) 40 require.Equal(t, "0147852369", c.F) 41 }) 42 43 t.Run("empty", func(t *testing.T) { 44 type Container struct { 45 F string `php:"f"` 46 } 47 48 var c Container 49 raw := `a:0:{}` 50 err := phpserialize.Unmarshal([]byte(raw), &c) 51 require.NoError(t, err) 52 require.Equal(t, "", c.F) 53 }) 54 } 55 56 func TestUnmarshal_stdClass(t *testing.T) { 57 raw := `O:8:"stdClass":1:{s:1:"a";s:13:"a str value q";}` 58 59 t.Run("struct", func(t *testing.T) { 60 var v struct { 61 A string `php:"a"` 62 } 63 64 require.NoError(t, phpserialize.Unmarshal([]byte(raw), &v)) 65 66 require.Equal(t, "a str value q", v.A) 67 }) 68 69 t.Run("any", func(t *testing.T) { 70 var v any 71 require.NoError(t, phpserialize.Unmarshal([]byte(raw), &v)) 72 73 m, ok := v.(map[string]any) 74 require.True(t, ok, "type cast fail") 75 76 require.Equal(t, "a str value q", m["a"]) 77 }) 78 79 t.Run("skip", func(t *testing.T) { 80 raw := `a:2:{s:1:"a";O:8:"stdClass":1:{s:1:"a";s:13:"a str value q";}s:5:"value";b:1;}` 81 var v struct { 82 Value bool `php:"value"` 83 } 84 require.NoError(t, phpserialize.Unmarshal([]byte(raw), &v)) 85 86 require.True(t, v.Value) 87 }) 88 } 89 90 func TestUnmarshal_struct_bytes(t *testing.T) { 91 t.Parallel() 92 93 t.Run("value", func(t *testing.T) { 94 type Container struct { 95 F []byte `php:"f1q"` 96 } 97 98 var c Container 99 raw := `a:1:{s:3:"f1q";s:10:"0147852369";}` 100 err := phpserialize.Unmarshal([]byte(raw), &c) 101 require.NoError(t, err) 102 require.Equal(t, []byte("0147852369"), c.F) 103 }) 104 105 t.Run("empty", func(t *testing.T) { 106 type Container struct { 107 F []byte `php:"f"` 108 } 109 110 var c Container 111 raw := `a:0:{}` 112 err := phpserialize.Unmarshal([]byte(raw), &c) 113 require.NoError(t, err) 114 require.Nil(t, c.F) 115 }) 116 } 117 118 func TestUnmarshal_struct_float(t *testing.T) { 119 t.Parallel() 120 121 t.Run("negative", func(t *testing.T) { 122 type Container struct { 123 F float64 `php:"f"` 124 } 125 var c Container 126 raw := `a:1:{s:1:"f";d:3.14;}` 127 err := phpserialize.Unmarshal([]byte(raw), &c) 128 require.NoError(t, err) 129 require.Equal(t, float64(3.14), c.F) 130 }) 131 132 t.Run("positive", func(t *testing.T) { 133 type Container struct { 134 F float64 `php:"f"` 135 } 136 var c Container 137 raw := `a:1:{s:1:"f";d:1;}` 138 err := phpserialize.Unmarshal([]byte(raw), &c) 139 require.NoError(t, err) 140 require.Equal(t, float64(1), c.F) 141 }) 142 143 t.Run("zero", func(t *testing.T) { 144 type Container struct { 145 F float64 `php:"f"` 146 } 147 var c Container 148 raw := `a:1:{s:1:"f";d:-3.14;}` 149 err := phpserialize.Unmarshal([]byte(raw), &c) 150 require.NoError(t, err) 151 require.Equal(t, float64(-3.14), c.F) 152 }) 153 154 t.Run("float32", func(t *testing.T) { 155 type Container struct { 156 F float32 `php:"f1q"` 157 } 158 159 var c Container 160 raw := `a:1:{s:3:"f1q";d:147852369;}` 161 err := phpserialize.Unmarshal([]byte(raw), &c) 162 require.NoError(t, err) 163 require.Equal(t, float32(147852369), c.F) 164 }) 165 166 t.Run("float64", func(t *testing.T) { 167 type Container struct { 168 F float64 `php:"f1q"` 169 } 170 171 var c Container 172 raw := `a:1:{s:3:"f1q";d:147852369;}` 173 err := phpserialize.Unmarshal([]byte(raw), &c) 174 require.NoError(t, err) 175 require.Equal(t, float64(147852369), c.F) 176 }) 177 178 } 179 180 func TestUnmarshal_struct_uint(t *testing.T) { 181 t.Parallel() 182 183 t.Run("uint", func(t *testing.T) { 184 type Container struct { 185 F uint `php:"f1q"` 186 } 187 188 var c Container 189 raw := `a:1:{s:3:"f1q";i:147852369;}` 190 err := phpserialize.Unmarshal([]byte(raw), &c) 191 require.NoError(t, err) 192 require.Equal(t, uint(147852369), c.F) 193 }) 194 195 t.Run("uint8", func(t *testing.T) { 196 type Container struct { 197 F uint8 `php:"f1q"` 198 } 199 200 var c Container 201 raw := `a:1:{s:3:"f1q";i:255;}` 202 err := phpserialize.Unmarshal([]byte(raw), &c) 203 require.NoError(t, err) 204 require.Equal(t, uint8(255), c.F) 205 }) 206 207 t.Run("uint16", func(t *testing.T) { 208 type Container struct { 209 F uint16 `php:"f1q"` 210 } 211 212 var c Container 213 raw := `a:1:{s:3:"f1q";i:574;}` 214 err := phpserialize.Unmarshal([]byte(raw), &c) 215 require.NoError(t, err) 216 require.Equal(t, uint16(574), c.F) 217 }) 218 219 t.Run("uint32", func(t *testing.T) { 220 type Container struct { 221 F uint32 `php:"f1q"` 222 } 223 224 var c Container 225 raw := `a:1:{s:3:"f1q";i:57400;}` 226 err := phpserialize.Unmarshal([]byte(raw), &c) 227 require.NoError(t, err) 228 require.Equal(t, uint32(57400), c.F) 229 }) 230 231 t.Run("uint64", func(t *testing.T) { 232 type Container struct { 233 F uint64 `php:"f1q"` 234 } 235 236 var c Container 237 raw := `a:1:{s:3:"f1q";i:5740000;}` 238 err := phpserialize.Unmarshal([]byte(raw), &c) 239 require.NoError(t, err) 240 require.Equal(t, uint64(5740000), c.F) 241 }) 242 } 243 244 func TestUnmarshal_struct_int(t *testing.T) { 245 t.Parallel() 246 247 t.Run("int", func(t *testing.T) { 248 type Container struct { 249 F int `php:"f1q"` 250 } 251 252 var c Container 253 raw := `a:1:{s:3:"f1q";i:147852369;}` 254 err := phpserialize.Unmarshal([]byte(raw), &c) 255 require.NoError(t, err) 256 require.Equal(t, int(147852369), c.F) 257 }) 258 259 t.Run("int8", func(t *testing.T) { 260 type Container struct { 261 F int8 `php:"f1q"` 262 } 263 264 var c Container 265 raw := `a:1:{s:3:"f1q";i:65;}` 266 err := phpserialize.Unmarshal([]byte(raw), &c) 267 require.NoError(t, err) 268 require.Equal(t, int8(65), c.F) 269 }) 270 271 t.Run("int16", func(t *testing.T) { 272 type Container struct { 273 F int16 `php:"f1q"` 274 } 275 276 var c Container 277 raw := `a:1:{s:3:"f1q";i:574;}` 278 err := phpserialize.Unmarshal([]byte(raw), &c) 279 require.NoError(t, err) 280 require.Equal(t, int16(574), c.F) 281 }) 282 283 t.Run("int32", func(t *testing.T) { 284 type Container struct { 285 F int32 `php:"f1q"` 286 } 287 288 var c Container 289 raw := `a:1:{s:3:"f1q";i:57400;}` 290 err := phpserialize.Unmarshal([]byte(raw), &c) 291 require.NoError(t, err) 292 require.Equal(t, int32(57400), c.F) 293 }) 294 295 t.Run("int64", func(t *testing.T) { 296 type Container struct { 297 F int64 `php:"f1q"` 298 } 299 300 var c Container 301 raw := `a:1:{s:3:"f1q";i:5740000;}` 302 err := phpserialize.Unmarshal([]byte(raw), &c) 303 require.NoError(t, err) 304 require.Equal(t, int64(5740000), c.F) 305 }) 306 } 307 308 func TestUnmarshal_slice(t *testing.T) { 309 t.Parallel() 310 311 t.Run("empty", func(t *testing.T) { 312 type Container struct { 313 Value []string `php:"value"` 314 } 315 316 var c Container 317 raw := `a:1:{s:5:"value";a:0:{}}` 318 err := phpserialize.Unmarshal([]byte(raw), &c) 319 require.NoError(t, err) 320 require.Len(t, c.Value, 0) 321 }) 322 323 t.Run("string", func(t *testing.T) { 324 type Container struct { 325 Value []string `php:"value"` 326 } 327 var c Container 328 raw := `a:3:{s:2:"bb";b:1;s:5:"value";a:3:{i:0;s:3:"one";i:1;s:3:"two";i:2;s:1:"q";}}` 329 err := phpserialize.Unmarshal([]byte(raw), &c) 330 require.NoError(t, err) 331 require.Equal(t, []string{"one", "two", "q"}, c.Value) 332 }) 333 334 t.Run("string more length", func(t *testing.T) { 335 type Container struct { 336 Value []string `php:"value"` 337 } 338 var c Container 339 raw := `a:1:{s:5:"value";a:6:{i:0;s:3:"one";i:1;s:3:"two";i:2;s:1:"q";i:3;s:1:"a";i:4;s:2:"zx";i:5;s:3:"abc";}}` 340 err := phpserialize.Unmarshal([]byte(raw), &c) 341 require.NoError(t, err) 342 require.Equal(t, []string{"one", "two", "q", "a", "zx"}, c.Value[:5]) 343 }) 344 } 345 346 func TestUnmarshal_array(t *testing.T) { 347 t.Parallel() 348 349 t.Run("empty", func(t *testing.T) { 350 type Container struct { 351 Value [5]string `php:"value"` 352 } 353 354 var c Container 355 raw := `a:1:{s:5:"value";a:0:{}}` 356 err := phpserialize.Unmarshal([]byte(raw), &c) 357 require.NoError(t, err) 358 require.Equal(t, [5]string{}, c.Value) 359 }) 360 361 t.Run("string less length", func(t *testing.T) { 362 type Container struct { 363 Value [5]string `php:"value"` 364 } 365 var c Container 366 raw := `a:1:{s:5:"value";a:3:{i:0;s:3:"one";i:1;s:3:"two";i:2;s:1:"q";}}` 367 err := phpserialize.Unmarshal([]byte(raw), &c) 368 require.NoError(t, err) 369 require.Equal(t, [5]string{"one", "two", "q"}, c.Value) 370 }) 371 372 t.Run("string more length", func(t *testing.T) { 373 type Container struct { 374 Value [5]string `php:"value"` 375 } 376 var c Container 377 raw := `a:1:{s:5:"value";a:6:{i:0;s:3:"one";i:1;s:3:"two";i:2;s:1:"q";i:3;s:1:"a";i:4;s:2:"zx";i:5;s:3:"abc";}}` 378 err := phpserialize.Unmarshal([]byte(raw), &c) 379 require.NoError(t, err) 380 require.Equal(t, [5]string{"one", "two", "q", "a", "zx"}, c.Value) 381 }) 382 } 383 384 func TestUnmarshal_skip_value(t *testing.T) { 385 type Container struct { 386 Value []string `php:"value"` 387 } 388 389 var c Container 390 raw := `a:3:{s:2:"bb";b:1;s:5:"value";a:3:{i:0;s:3:"one";i:1;s:3:"two";i:2;s:1:"q";}s:6:"value2";a:3:{i:0;s:1:"1";i:1;s:1:"2";i:2;s:1:"3";}}` 391 err := phpserialize.Unmarshal([]byte(raw), &c) 392 require.NoError(t, err) 393 require.Equal(t, []string{"one", "two", "q"}, c.Value) 394 } 395 396 var _ phpserialize.Unmarshaler = (*unmarshaler)(nil) 397 398 type unmarshaler []byte 399 400 func (u *unmarshaler) UnmarshalPHP(bytes []byte) error { 401 *u = append((*u)[0:0], bytes...) 402 403 return nil 404 } 405 406 func TestUnmarshal_unmarshaler(t *testing.T) { 407 t.Parallel() 408 type Container struct { 409 Value unmarshaler `php:"value"` 410 } 411 412 var c Container 413 raw := `a:1:{s:5:"value";a:3:{i:0;s:3:"one";i:1;s:3:"two";i:2;s:1:"q";}}` 414 err := phpserialize.Unmarshal([]byte(raw), &c) 415 require.NoError(t, err) 416 require.Equal(t, `a:3:{i:0;s:3:"one";i:1;s:3:"two";i:2;s:1:"q";}`, string(c.Value)) 417 } 418 419 func TestUnmarshal_string_wrapper(t *testing.T) { 420 t.Parallel() 421 422 type Container struct { 423 Value int `php:"value,string"` 424 } 425 426 var c Container 427 raw := `a:1:{s:5:"value";s:3:"233";}` 428 err := phpserialize.Unmarshal([]byte(raw), &c) 429 require.NoError(t, err) 430 require.Equal(t, int(233), c.Value) 431 } 432 433 func TestUnmarshal_map(t *testing.T) { 434 t.Parallel() 435 436 t.Run("map[string]string", func(t *testing.T) { 437 raw := `a:1:{s:5:"value";a:5:{s:3:"one";s:1:"1";s:3:"two";s:1:"2";s:5:"three";s:1:"3";s:4:"four";s:1:"4";s:4:"five";s:1:"5";}}` 438 var c struct { 439 Value map[string]string `php:"value"` 440 } 441 442 err := phpserialize.Unmarshal([]byte(raw), &c) 443 require.NoError(t, err) 444 require.Equal(t, map[string]string{ 445 "one": "1", 446 "two": "2", 447 "three": "3", 448 "four": "4", 449 "five": "5", 450 }, c.Value) 451 }) 452 453 t.Run("map[any]string", func(t *testing.T) { 454 raw := `a:1:{s:5:"value";a:5:{i:1;s:3:"one";i:2;s:3:"two";i:3;s:5:"three";i:4;s:4:"four";i:5;s:4:"five";}}` 455 var c struct { 456 Value map[any]string `php:"value"` 457 } 458 459 err := phpserialize.Unmarshal([]byte(raw), &c) 460 require.NoError(t, err) 461 require.Equal(t, map[any]string{ 462 int64(1): "one", 463 int64(2): "two", 464 int64(3): "three", 465 int64(4): "four", 466 int64(5): "five", 467 }, c.Value) 468 }) 469 470 t.Run("any", func(t *testing.T) { 471 raw := `a:1:{s:5:"value";a:5:{i:1;s:3:"one";i:2;s:3:"two";i:3;s:5:"three";i:4;s:4:"four";i:5;s:4:"five";}}` 472 var c struct { 473 Value any `php:"value"` 474 } 475 476 err := phpserialize.Unmarshal([]byte(raw), &c) 477 require.NoError(t, err) 478 require.Equal(t, map[any]any{ 479 int64(1): "one", 480 int64(2): "two", 481 int64(3): "three", 482 int64(4): "four", 483 int64(5): "five", 484 }, c.Value) 485 }) 486 } 487 488 func TestUnmarshal_ptr_string(t *testing.T) { 489 t.Parallel() 490 491 t.Run("value", func(t *testing.T) { 492 var c struct { 493 F *string `php:"f1q"` 494 } 495 496 raw := `a:1:{s:3:"f1q";s:10:"0147852369";}` 497 err := phpserialize.Unmarshal([]byte(raw), &c) 498 require.NoError(t, err) 499 require.NotNil(t, c.F) 500 require.Equal(t, "0147852369", *c.F) 501 }) 502 503 t.Run("empty", func(t *testing.T) { 504 var c struct { 505 F *string `php:"f"` 506 } 507 508 raw := `a:0:{}` 509 err := phpserialize.Unmarshal([]byte(raw), &c) 510 require.NoError(t, err) 511 require.Nil(t, c.F) 512 }) 513 514 t.Run("nested", func(t *testing.T) { 515 var c struct { 516 F **string `php:"f"` 517 } 518 519 raw := `a:0:{}` 520 err := phpserialize.Unmarshal([]byte(raw), &c) 521 require.Error(t, err) 522 }) 523 } 524 525 func TestUnmarshal_anonymous_field(t *testing.T) { 526 type N struct { 527 A int 528 B int 529 } 530 531 type M struct { 532 N 533 C int 534 } 535 536 var v M 537 538 require.NoError(t, phpserialize.Unmarshal([]byte(`a:4:{s:1:"A";i:3;s:1:"B";i:2;s:1:"C";i:1;}`), &v)) 539 require.Equal(t, M{N: N{ 540 A: 3, 541 B: 2, 542 }, C: 1}, v) 543 } 544 545 func TestUnmarshal_empty_input(t *testing.T) { 546 t.Run("slice", func(t *testing.T) { 547 var data []int 548 require.NoError(t, phpserialize.Unmarshal([]byte(""), &data)) 549 }) 550 t.Run("array", func(t *testing.T) { 551 var data [5]int 552 require.NoError(t, phpserialize.Unmarshal([]byte(""), &data)) 553 }) 554 t.Run("map", func(t *testing.T) { 555 var data map[uint]int 556 require.NoError(t, phpserialize.Unmarshal([]byte(""), &data)) 557 }) 558 t.Run("interface", func(t *testing.T) { 559 var data any 560 require.NoError(t, phpserialize.Unmarshal([]byte(""), &data)) 561 }) 562 t.Run("string", func(t *testing.T) { 563 var data string 564 require.NoError(t, phpserialize.Unmarshal([]byte(""), &data)) 565 }) 566 t.Run("int", func(t *testing.T) { 567 var data int 568 require.NoError(t, phpserialize.Unmarshal([]byte(""), &data)) 569 }) 570 571 t.Run("uint", func(t *testing.T) { 572 var data uint 573 require.NoError(t, phpserialize.Unmarshal([]byte(""), &data)) 574 }) 575 576 t.Run("bool", func(t *testing.T) { 577 var data bool 578 require.NoError(t, phpserialize.Unmarshal([]byte(""), &data)) 579 }) 580 } 581 582 func TestUnmarshal_as_string_2(t *testing.T) { 583 type ID uint32 584 type Type uint8 585 type Item struct { 586 ID ID `php:"eid,string"` 587 Type Type `php:"type"` 588 } 589 type Collection = map[ID]Item 590 591 raw := `a:7:{i:1087180;a:2:{s:3:"eid";s:7:"1087180";s:4:"type";i:2;}i:1087181;a:2:{s:3:"eid";s:7:"1087181";s:4:"type";i:2;}i:1087182;a:2:{s:3:"eid";s:7:"1087182";s:4:"type";i:2;}i:1087183;a:2:{s:3:"eid";s:7:"1087183";s:4:"type";i:2;}i:1087184;a:2:{s:3:"eid";s:7:"1087184";s:4:"type";i:2;}i:1087185;a:2:{s:3:"eid";s:7:"1087185";s:4:"type";i:2;}i:1087186;a:2:{s:3:"eid";s:7:"1087186";s:4:"type";i:2;}}` 592 593 var data Collection 594 595 err := phpserialize.Unmarshal([]byte(raw), &data) 596 require.NoError(t, err) 597 598 } 599 600 func TestUnmarshal_null_array_1(t *testing.T) { 601 raw := `a:0:{}` 602 603 type Tag struct { 604 Name *string `php:"tag_name"` 605 Count int `php:"result,string"` 606 } 607 608 var tags []Tag 609 610 err := phpserialize.Unmarshal([]byte(raw), &tags) 611 require.NoError(t, err) 612 } 613 614 func TestUnmarshal_null_array_2(t *testing.T) { 615 raw := `a:4:{s:1:"a";i:2;s:4:"Test";a:0:{}s:1:"b";a:0:{}s:1:"o";i:1;}` 616 617 var data any 618 619 err := phpserialize.Unmarshal([]byte(raw), &data) 620 require.NoError(t, err) 621 622 require.Equal(t, data, map[any]any{ 623 "a": int64(2), 624 "o": int64(1), 625 "Test": map[any]any{}, 626 "b": map[any]any{}, 627 }) 628 }