1<?php 2 3require_once('test_base.php'); 4require_once('test_util.php'); 5 6use Google\Protobuf\Internal\RepeatedField; 7use Google\Protobuf\Internal\GPBType; 8use Foo\TestMessage; 9use Foo\TestMessage\Sub; 10 11class ArrayTest extends TestBase 12{ 13 14 ######################################################### 15 # Test int32 field. 16 ######################################################### 17 18 public function testInt32() 19 { 20 $arr = new RepeatedField(GPBType::INT32); 21 22 // Test append. 23 $arr[] = MAX_INT32; 24 $this->assertSame(MAX_INT32, $arr[0]); 25 $arr[] = MIN_INT32; 26 $this->assertSame(MIN_INT32, $arr[1]); 27 28 $arr[] = 1.1; 29 $this->assertSame(1, $arr[2]); 30 $arr[] = MAX_INT32_FLOAT; 31 $this->assertSame(MAX_INT32, $arr[3]); 32 $arr[] = MAX_INT32_FLOAT; 33 $this->assertSame(MAX_INT32, $arr[4]); 34 35 $arr[] = '2'; 36 $this->assertSame(2, $arr[5]); 37 $arr[] = '3.1'; 38 $this->assertSame(3, $arr[6]); 39 $arr[] = MAX_INT32_STRING; 40 $this->assertSame(MAX_INT32, $arr[7]); 41 42 $this->assertEquals(8, count($arr)); 43 44 for ($i = 0; $i < count($arr); $i++) { 45 $arr[$i] = 0; 46 $this->assertSame(0, $arr[$i]); 47 } 48 49 // Test set. 50 $arr[0] = MAX_INT32; 51 $this->assertSame(MAX_INT32, $arr[0]); 52 $arr[1] = MIN_INT32; 53 $this->assertSame(MIN_INT32, $arr[1]); 54 55 $arr[2] = 1.1; 56 $this->assertSame(1, $arr[2]); 57 $arr[3] = MAX_INT32_FLOAT; 58 $this->assertSame(MAX_INT32, $arr[3]); 59 $arr[4] = MAX_INT32_FLOAT; 60 $this->assertSame(MAX_INT32, $arr[4]); 61 62 $arr[5] = '2'; 63 $this->assertSame(2, $arr[5]); 64 $arr[6] = '3.1'; 65 $this->assertSame(3, $arr[6]); 66 $arr[7] = MAX_INT32_STRING; 67 $this->assertSame(MAX_INT32, $arr[7]); 68 69 // Test foreach. 70 $arr = new RepeatedField(GPBType::INT32); 71 for ($i = 0; $i < 3; $i++) { 72 $arr[] = $i; 73 } 74 $i = 0; 75 foreach ($arr as $val) { 76 $this->assertSame($i++, $val); 77 } 78 $this->assertSame(3, $i); 79 } 80 81 ######################################################### 82 # Test uint32 field. 83 ######################################################### 84 85 public function testUint32() 86 { 87 $arr = new RepeatedField(GPBType::UINT32); 88 89 // Test append. 90 $arr[] = MAX_UINT32; 91 $this->assertSame(-1, $arr[0]); 92 $arr[] = -1; 93 $this->assertSame(-1, $arr[1]); 94 $arr[] = MIN_UINT32; 95 $this->assertSame(MIN_UINT32, $arr[2]); 96 97 $arr[] = 1.1; 98 $this->assertSame(1, $arr[3]); 99 $arr[] = MAX_UINT32_FLOAT; 100 $this->assertSame(-1, $arr[4]); 101 $arr[] = -1.0; 102 $this->assertSame(-1, $arr[5]); 103 $arr[] = MIN_UINT32_FLOAT; 104 $this->assertSame(MIN_UINT32, $arr[6]); 105 106 $arr[] = '2'; 107 $this->assertSame(2, $arr[7]); 108 $arr[] = '3.1'; 109 $this->assertSame(3, $arr[8]); 110 $arr[] = MAX_UINT32_STRING; 111 $this->assertSame(-1, $arr[9]); 112 $arr[] = '-1.0'; 113 $this->assertSame(-1, $arr[10]); 114 $arr[] = MIN_UINT32_STRING; 115 $this->assertSame(MIN_UINT32, $arr[11]); 116 117 $this->assertEquals(12, count($arr)); 118 119 for ($i = 0; $i < count($arr); $i++) { 120 $arr[$i] = 0; 121 $this->assertSame(0, $arr[$i]); 122 } 123 124 // Test set. 125 $arr[0] = MAX_UINT32; 126 $this->assertSame(-1, $arr[0]); 127 $arr[1] = -1; 128 $this->assertSame(-1, $arr[1]); 129 $arr[2] = MIN_UINT32; 130 $this->assertSame(MIN_UINT32, $arr[2]); 131 132 $arr[3] = 1.1; 133 $this->assertSame(1, $arr[3]); 134 $arr[4] = MAX_UINT32_FLOAT; 135 $this->assertSame(-1, $arr[4]); 136 $arr[5] = -1.0; 137 $this->assertSame(-1, $arr[5]); 138 $arr[6] = MIN_UINT32_FLOAT; 139 $this->assertSame(MIN_UINT32, $arr[6]); 140 141 $arr[7] = '2'; 142 $this->assertSame(2, $arr[7]); 143 $arr[8] = '3.1'; 144 $this->assertSame(3, $arr[8]); 145 $arr[9] = MAX_UINT32_STRING; 146 $this->assertSame(-1, $arr[9]); 147 $arr[10] = '-1.0'; 148 $this->assertSame(-1, $arr[10]); 149 $arr[11] = MIN_UINT32_STRING; 150 $this->assertSame(MIN_UINT32, $arr[11]); 151 } 152 153 ######################################################### 154 # Test int64 field. 155 ######################################################### 156 157 public function testInt64() 158 { 159 $arr = new RepeatedField(GPBType::INT64); 160 161 // Test append. 162 $arr[] = MAX_INT64; 163 $arr[] = MIN_INT64; 164 $arr[] = 1.1; 165 $arr[] = '2'; 166 $arr[] = '3.1'; 167 $arr[] = MAX_INT64_STRING; 168 $arr[] = MIN_INT64_STRING; 169 if (PHP_INT_SIZE == 4) { 170 $this->assertSame(MAX_INT64, $arr[0]); 171 $this->assertSame(MIN_INT64, $arr[1]); 172 $this->assertSame('1', $arr[2]); 173 $this->assertSame('2', $arr[3]); 174 $this->assertSame('3', $arr[4]); 175 $this->assertSame(MAX_INT64_STRING, $arr[5]); 176 $this->assertSame(MIN_INT64_STRING, $arr[6]); 177 } else { 178 $this->assertSame(MAX_INT64, $arr[0]); 179 $this->assertSame(MIN_INT64, $arr[1]); 180 $this->assertSame(1, $arr[2]); 181 $this->assertSame(2, $arr[3]); 182 $this->assertSame(3, $arr[4]); 183 $this->assertSame(MAX_INT64, $arr[5]); 184 $this->assertSame(MIN_INT64, $arr[6]); 185 } 186 187 188 $this->assertEquals(7, count($arr)); 189 190 for ($i = 0; $i < count($arr); $i++) { 191 $arr[$i] = 0; 192 if (PHP_INT_SIZE == 4) { 193 $this->assertSame('0', $arr[$i]); 194 } else { 195 $this->assertSame(0, $arr[$i]); 196 } 197 } 198 199 // Test set. 200 $arr[0] = MAX_INT64; 201 $arr[1] = MIN_INT64; 202 $arr[2] = 1.1; 203 $arr[3] = '2'; 204 $arr[4] = '3.1'; 205 $arr[5] = MAX_INT64_STRING; 206 $arr[6] = MIN_INT64_STRING; 207 208 if (PHP_INT_SIZE == 4) { 209 $this->assertSame(MAX_INT64_STRING, $arr[0]); 210 $this->assertSame(MIN_INT64_STRING, $arr[1]); 211 $this->assertSame('1', $arr[2]); 212 $this->assertSame('2', $arr[3]); 213 $this->assertSame('3', $arr[4]); 214 $this->assertSame(MAX_INT64_STRING, $arr[5]); 215 $this->assertEquals(MIN_INT64_STRING, $arr[6]); 216 } else { 217 $this->assertSame(MAX_INT64, $arr[0]); 218 $this->assertSame(MIN_INT64, $arr[1]); 219 $this->assertSame(1, $arr[2]); 220 $this->assertSame(2, $arr[3]); 221 $this->assertSame(3, $arr[4]); 222 $this->assertSame(MAX_INT64, $arr[5]); 223 $this->assertEquals(MIN_INT64, $arr[6]); 224 } 225 } 226 227 ######################################################### 228 # Test uint64 field. 229 ######################################################### 230 231 public function testUint64() 232 { 233 $arr = new RepeatedField(GPBType::UINT64); 234 235 // Test append. 236 $arr[] = MAX_UINT64; 237 $arr[] = 1.1; 238 $arr[] = '2'; 239 $arr[] = '3.1'; 240 $arr[] = MAX_UINT64_STRING; 241 242 if (PHP_INT_SIZE == 4) { 243 $this->assertSame(MAX_UINT64_STRING, $arr[0]); 244 $this->assertSame('1', $arr[1]); 245 $this->assertSame('2', $arr[2]); 246 $this->assertSame('3', $arr[3]); 247 $this->assertSame(MAX_UINT64_STRING, $arr[4]); 248 } else { 249 $this->assertSame(MAX_UINT64, $arr[0]); 250 $this->assertSame(1, $arr[1]); 251 $this->assertSame(2, $arr[2]); 252 $this->assertSame(3, $arr[3]); 253 $this->assertSame(MAX_UINT64, $arr[4]); 254 $this->assertSame(5, count($arr)); 255 } 256 257 $this->assertSame(5, count($arr)); 258 259 for ($i = 0; $i < count($arr); $i++) { 260 $arr[$i] = 0; 261 if (PHP_INT_SIZE == 4) { 262 $this->assertSame('0', $arr[$i]); 263 } else { 264 $this->assertSame(0, $arr[$i]); 265 } 266 } 267 268 // Test set. 269 $arr[0] = MAX_UINT64; 270 $arr[1] = 1.1; 271 $arr[2] = '2'; 272 $arr[3] = '3.1'; 273 $arr[4] = MAX_UINT64_STRING; 274 275 if (PHP_INT_SIZE == 4) { 276 $this->assertSame(MAX_UINT64_STRING, $arr[0]); 277 $this->assertSame('1', $arr[1]); 278 $this->assertSame('2', $arr[2]); 279 $this->assertSame('3', $arr[3]); 280 $this->assertSame(MAX_UINT64_STRING, $arr[4]); 281 } else { 282 $this->assertSame(MAX_UINT64, $arr[0]); 283 $this->assertSame(1, $arr[1]); 284 $this->assertSame(2, $arr[2]); 285 $this->assertSame(3, $arr[3]); 286 $this->assertSame(MAX_UINT64, $arr[4]); 287 } 288 } 289 290 ######################################################### 291 # Test float field. 292 ######################################################### 293 294 public function testFloat() 295 { 296 $arr = new RepeatedField(GPBType::FLOAT); 297 298 // Test append. 299 $arr[] = 1; 300 $this->assertFloatEquals(1.0, $arr[0], MAX_FLOAT_DIFF); 301 302 $arr[] = 1.1; 303 $this->assertFloatEquals(1.1, $arr[1], MAX_FLOAT_DIFF); 304 305 $arr[] = '2'; 306 $this->assertFloatEquals(2.0, $arr[2], MAX_FLOAT_DIFF); 307 $arr[] = '3.1'; 308 $this->assertFloatEquals(3.1, $arr[3], MAX_FLOAT_DIFF); 309 310 $this->assertEquals(4, count($arr)); 311 312 for ($i = 0; $i < count($arr); $i++) { 313 $arr[$i] = 0; 314 $this->assertSame(0.0, $arr[$i]); 315 } 316 317 // Test set. 318 $arr[0] = 1; 319 $this->assertFloatEquals(1.0, $arr[0], MAX_FLOAT_DIFF); 320 321 $arr[1] = 1.1; 322 $this->assertFloatEquals(1.1, $arr[1], MAX_FLOAT_DIFF); 323 324 $arr[2] = '2'; 325 $this->assertFloatEquals(2.0, $arr[2], MAX_FLOAT_DIFF); 326 $arr[3] = '3.1'; 327 $this->assertFloatEquals(3.1, $arr[3], MAX_FLOAT_DIFF); 328 } 329 330 ######################################################### 331 # Test double field. 332 ######################################################### 333 334 public function testDouble() 335 { 336 $arr = new RepeatedField(GPBType::DOUBLE); 337 338 // Test append. 339 $arr[] = 1; 340 $this->assertFloatEquals(1.0, $arr[0], MAX_FLOAT_DIFF); 341 342 $arr[] = 1.1; 343 $this->assertFloatEquals(1.1, $arr[1], MAX_FLOAT_DIFF); 344 345 $arr[] = '2'; 346 $this->assertFloatEquals(2.0, $arr[2], MAX_FLOAT_DIFF); 347 $arr[] = '3.1'; 348 $this->assertFloatEquals(3.1, $arr[3], MAX_FLOAT_DIFF); 349 350 $this->assertEquals(4, count($arr)); 351 352 for ($i = 0; $i < count($arr); $i++) { 353 $arr[$i] = 0; 354 $this->assertSame(0.0, $arr[$i]); 355 } 356 357 // Test set. 358 $arr[0] = 1; 359 $this->assertFloatEquals(1.0, $arr[0], MAX_FLOAT_DIFF); 360 361 $arr[1] = 1.1; 362 $this->assertFloatEquals(1.1, $arr[1], MAX_FLOAT_DIFF); 363 364 $arr[2] = '2'; 365 $this->assertFloatEquals(2.0, $arr[2], MAX_FLOAT_DIFF); 366 $arr[3] = '3.1'; 367 $this->assertFloatEquals(3.1, $arr[3], MAX_FLOAT_DIFF); 368 } 369 370 ######################################################### 371 # Test bool field. 372 ######################################################### 373 374 public function testBool() 375 { 376 $arr = new RepeatedField(GPBType::BOOL); 377 378 // Test append. 379 $arr[] = true; 380 $this->assertSame(true, $arr[0]); 381 382 $arr[] = -1; 383 $this->assertSame(true, $arr[1]); 384 385 $arr[] = 1.1; 386 $this->assertSame(true, $arr[2]); 387 388 $arr[] = ''; 389 $this->assertSame(false, $arr[3]); 390 391 $this->assertEquals(4, count($arr)); 392 393 for ($i = 0; $i < count($arr); $i++) { 394 $arr[$i] = 0; 395 $this->assertSame(false, $arr[$i]); 396 } 397 398 // Test set. 399 $arr[0] = true; 400 $this->assertSame(true, $arr[0]); 401 402 $arr[1] = -1; 403 $this->assertSame(true, $arr[1]); 404 405 $arr[2] = 1.1; 406 $this->assertSame(true, $arr[2]); 407 408 $arr[3] = ''; 409 $this->assertSame(false, $arr[3]); 410 } 411 412 ######################################################### 413 # Test string field. 414 ######################################################### 415 416 public function testString() 417 { 418 $arr = new RepeatedField(GPBType::STRING); 419 420 // Test append. 421 $arr[] = 'abc'; 422 $this->assertSame('abc', $arr[0]); 423 424 $arr[] = 1; 425 $this->assertSame('1', $arr[1]); 426 427 $arr[] = 1.1; 428 $this->assertSame('1.1', $arr[2]); 429 430 $arr[] = true; 431 $this->assertSame('1', $arr[3]); 432 433 $this->assertEquals(4, count($arr)); 434 435 for ($i = 0; $i < count($arr); $i++) { 436 $arr[$i] = ''; 437 $this->assertSame('', $arr[$i]); 438 } 439 440 // Test set. 441 $arr[0] = 'abc'; 442 $this->assertSame('abc', $arr[0]); 443 444 $arr[1] = 1; 445 $this->assertSame('1', $arr[1]); 446 447 $arr[2] = 1.1; 448 $this->assertSame('1.1', $arr[2]); 449 450 $arr[3] = true; 451 $this->assertSame('1', $arr[3]); 452 } 453 454 ######################################################### 455 # Test message field. 456 ######################################################### 457 458 public function testMessage() 459 { 460 $arr = new RepeatedField(GPBType::MESSAGE, Sub::class); 461 462 // Test append. 463 $sub_m = new Sub(); 464 $sub_m->setA(1); 465 $arr[] = $sub_m; 466 $this->assertSame(1, $arr[0]->getA()); 467 468 $this->assertEquals(1, count($arr)); 469 470 // Test set. 471 $sub_m = new Sub(); 472 $sub_m->setA(2); 473 $arr[0] = $sub_m; 474 $this->assertSame(2, $arr[0]->getA()); 475 476 // Test foreach. 477 $arr = new RepeatedField(GPBType::MESSAGE, Sub::class); 478 for ($i = 0; $i < 3; $i++) { 479 $arr[] = new Sub(); 480 $arr[$i]->setA($i); 481 } 482 $i = 0; 483 foreach ($arr as $val) { 484 $this->assertSame($i++, $val->getA()); 485 } 486 $this->assertSame(3, $i); 487 } 488 489 ######################################################### 490 # Test offset type 491 ######################################################### 492 493 public function testOffset() 494 { 495 $arr = new RepeatedField(GPBType::INT32); 496 $arr[] = 0; 497 498 $arr[0] = 1; 499 $this->assertSame(1, $arr[0]); 500 $this->assertSame(1, count($arr)); 501 502 $arr['0'] = 2; 503 $this->assertSame(2, $arr['0']); 504 $this->assertSame(2, $arr[0]); 505 $this->assertSame(1, count($arr)); 506 507 $arr[0.0] = 3; 508 $this->assertSame(3, $arr[0.0]); 509 $this->assertSame(1, count($arr)); 510 } 511 512 public function testInsertRemoval() 513 { 514 $arr = new RepeatedField(GPBType::INT32); 515 516 $arr[] = 0; 517 $arr[] = 1; 518 $arr[] = 2; 519 $this->assertSame(3, count($arr)); 520 521 unset($arr[2]); 522 $this->assertSame(2, count($arr)); 523 $this->assertSame(0, $arr[0]); 524 $this->assertSame(1, $arr[1]); 525 526 $arr[] = 3; 527 $this->assertSame(3, count($arr)); 528 $this->assertSame(0, $arr[0]); 529 $this->assertSame(1, $arr[1]); 530 $this->assertSame(3, $arr[2]); 531 } 532 533 ######################################################### 534 # Test reference in array 535 ######################################################### 536 537 public function testArrayElementIsReferenceInSetters() 538 { 539 // Bool elements 540 $values = [true]; 541 array_walk($values, function (&$value) {}); 542 $m = new TestMessage(); 543 $m->setRepeatedBool($values); 544 545 // Int32 elements 546 $values = [1]; 547 array_walk($values, function (&$value) {}); 548 $m = new TestMessage(); 549 $m->setRepeatedInt32($values); 550 551 // Double elements 552 $values = [1.0]; 553 array_walk($values, function (&$value) {}); 554 $m = new TestMessage(); 555 $m->setRepeatedDouble($values); 556 557 // String elements 558 $values = ['a']; 559 array_walk($values, function (&$value) {}); 560 $m = new TestMessage(); 561 $m->setRepeatedString($values); 562 563 // Message elements 564 $m = new TestMessage(); 565 $subs = [1, 2]; 566 foreach ($subs as &$sub) { 567 $sub = new Sub(['a' => $sub]); 568 } 569 $m->setRepeatedMessage($subs); 570 571 $this->assertTrue(true); 572 } 573 574 ######################################################### 575 # Test memory leak 576 ######################################################### 577 578 public function testCycleLeak() 579 { 580 if (getenv("USE_ZEND_ALLOC") === "0") { 581 // If we are disabling Zend's internal allocator (as we do for 582 // Valgrind tests, for example) then memory_get_usage() will not 583 // return a useful value. 584 $this->markTestSkipped(); 585 return; 586 } 587 588 gc_collect_cycles(); 589 $arr = new RepeatedField(GPBType::MESSAGE, TestMessage::class); 590 $arr[] = new TestMessage; 591 $arr[0]->SetRepeatedRecursive($arr); 592 593 // Clean up memory before test. 594 gc_collect_cycles(); 595 $start = memory_get_usage(); 596 unset($arr); 597 598 // Explicitly trigger garbage collection. 599 gc_collect_cycles(); 600 601 $end = memory_get_usage(); 602 $this->assertLessThan($start, $end); 603 } 604 605 ######################################################### 606 # Test incorrect types 607 ######################################################### 608 609 public function testAppendNull() 610 { 611 $this->expectException(TypeError::class); 612 $arr = new RepeatedField(GPBType::MESSAGE, TestMessage::class); 613 $arr[] = null; 614 } 615 616 ######################################################### 617 # Test equality 618 ######################################################### 619 620 public function testEquality() 621 { 622 $arr = new RepeatedField(GPBType::INT32); 623 $arr2 = new RepeatedField(GPBType::INT32); 624 625 $this->assertTrue($arr == $arr2); 626 627 $arr[] = 0; 628 $arr[] = 1; 629 $arr[] = 2; 630 631 $this->assertFalse($arr == $arr2); 632 633 $arr2[] = 0; 634 $arr2[] = 1; 635 $arr2[] = 2; 636 637 $this->assertTrue($arr == $arr2); 638 639 // Arrays of different types always compare false. 640 $this->assertFalse(new RepeatedField(GPBType::INT32) == 641 new RepeatedField(GPBType::INT64)); 642 $this->assertFalse( 643 new RepeatedField(GPBType::MESSAGE, TestMessage::class) == 644 new RepeatedField(GPBType::MESSAGE, Sub::class)); 645 } 646 647 ######################################################### 648 # Test clone 649 ######################################################### 650 651 public function testClone() 652 { 653 $arr = new RepeatedField(GPBType::MESSAGE, TestMessage::class); 654 $arr[] = new TestMessage; 655 $arr2 = clone $arr; 656 $this->assertSame($arr[0], $arr2[0]); 657 } 658} 659